audacia/src/menus/ViewMenus.cpp

493 lines
15 KiB
C++
Raw Normal View History

#include "../CommonCommandFlags.h"
2018-10-23 11:33:06 +00:00
#include "../Menus.h"
#include "../Prefs.h"
#include "../Project.h"
#include "../ProjectHistory.h"
#include "../ProjectSettings.h"
2019-05-29 16:05:22 +00:00
#include "../ProjectWindow.h"
#include "../Track.h"
2019-06-18 16:40:38 +00:00
#include "../TrackInfo.h"
2018-10-23 11:33:06 +00:00
#include "../TrackPanel.h"
#include "../UndoManager.h"
#include "../ViewInfo.h"
2018-10-23 11:33:06 +00:00
#include "../commands/CommandContext.h"
#include "../commands/CommandManager.h"
#include "../prefs/GUIPrefs.h"
2018-10-23 11:33:06 +00:00
#include "../prefs/TracksPrefs.h"
2019-06-18 15:29:38 +00:00
#include "../tracks/ui/TrackView.h"
2018-10-23 11:33:06 +00:00
#ifdef EXPERIMENTAL_EFFECTS_RACK
2019-07-21 13:20:02 +00:00
#include "../effects/EffectUI.h"
#endif
2018-10-23 11:33:06 +00:00
#include <wx/scrolbar.h>
// private helper classes and functions
namespace {
2018-10-27 23:47:48 +00:00
double GetZoomOfSelection( const AudacityProject &project )
{
auto &viewInfo = ViewInfo::Get( project );
auto &window = ProjectWindow::Get( project );
2018-10-27 23:47:48 +00:00
const double lowerBound =
std::max(viewInfo.selectedRegion.t0(),
window.ScrollingLowerBoundTime());
2018-10-27 23:47:48 +00:00
const double denom =
viewInfo.selectedRegion.t1() - lowerBound;
if (denom <= 0.0)
return viewInfo.GetZoom();
// LL: The "-1" is just a hack to get around an issue where zooming to
// selection doesn't actually get the entire selected region within the
// visible area. This causes a problem with scrolling at end of playback
// where the selected region may be scrolled off the left of the screen.
// I know this isn't right, but until the real rounding or 1-off issue is
// found, this will have to work.
// PRL: Did I fix this? I am not sure, so I leave the hack in place.
// Fixes might have resulted from commits
// 1b8f44d0537d987c59653b11ed75a842b48896ea and
// e7c7bb84a966c3b3cc4b3a9717d5f247f25e7296
auto width = viewInfo.GetTracksUsableWidth();
2018-10-27 23:47:48 +00:00
return (width - 1) / denom;
}
double GetZoomOfPreset( const AudacityProject &project, int preset )
{
// Sets a limit on how far we will zoom out as a factor over zoom to fit.
const double maxZoomOutFactor = 4.0;
// Sets how many pixels we allow for one uint, such as seconds.
const double pixelsPerUnit = 5.0;
double result = 1.0;
auto &window = ProjectWindow::Get( project );
double zoomToFit = window.GetZoomOfToFit();
using namespace WaveTrackViewConstants;
2018-10-27 23:47:48 +00:00
switch( preset ){
default:
case kZoomDefault:
2018-10-27 23:47:48 +00:00
result = ZoomInfo::GetDefaultZoom();
break;
case kZoomToFit:
2018-10-27 23:47:48 +00:00
result = zoomToFit;
break;
case kZoomToSelection:
2018-10-27 23:47:48 +00:00
result = GetZoomOfSelection( project );
break;
case kZoomMinutes:
2018-10-27 23:47:48 +00:00
result = pixelsPerUnit * 1.0/60;
break;
case kZoomSeconds:
2018-10-27 23:47:48 +00:00
result = pixelsPerUnit * 1.0;
break;
case kZoom5ths:
2018-10-27 23:47:48 +00:00
result = pixelsPerUnit * 5.0;
break;
case kZoom10ths:
2018-10-27 23:47:48 +00:00
result = pixelsPerUnit * 10.0;
break;
case kZoom20ths:
2018-10-27 23:47:48 +00:00
result = pixelsPerUnit * 20.0;
break;
case kZoom50ths:
2018-10-27 23:47:48 +00:00
result = pixelsPerUnit * 50.0;
break;
case kZoom100ths:
2018-10-27 23:47:48 +00:00
result = pixelsPerUnit * 100.0;
break;
case kZoom500ths:
2018-10-27 23:47:48 +00:00
result = pixelsPerUnit * 500.0;
break;
case kZoomMilliSeconds:
2018-10-27 23:47:48 +00:00
result = pixelsPerUnit * 1000.0;
break;
case kZoomSamples:
2018-10-27 23:47:48 +00:00
result = 44100.0;
break;
case kZoom4To1:
2018-10-27 23:47:48 +00:00
result = 44100.0 * 4;
break;
case kMaxZoom:
2018-10-27 23:47:48 +00:00
result = ZoomInfo::GetMaxZoom();
break;
};
if( result < (zoomToFit/maxZoomOutFactor) )
result = zoomToFit / maxZoomOutFactor;
return result;
}
2018-10-23 11:33:06 +00:00
}
namespace {
2018-10-23 11:33:06 +00:00
void DoZoomFitV(AudacityProject &project)
{
auto &viewInfo = ViewInfo::Get( project );
auto &tracks = TrackList::Get( project );
2018-10-23 11:33:06 +00:00
// Only nonminimized audio tracks will be resized
2019-06-18 15:29:38 +00:00
auto range = tracks.Any<AudioTrack>()
- [](const Track *pTrack){
return TrackView::Get( *pTrack ).GetMinimized(); };
2018-10-23 11:33:06 +00:00
auto count = range.size();
if (count == 0)
return;
// Find total height to apportion
auto height = viewInfo.GetHeight();
2018-10-23 11:33:06 +00:00
height -= 28;
// The height of minimized and non-audio tracks cannot be apportioned
height -=
tracks.Any().sum( TrackView::GetTrackHeight )
- range.sum( TrackView::GetTrackHeight );
2018-10-23 11:33:06 +00:00
// Give each resized track the average of the remaining height
// Bug 2803: Cast count to int, because otherwise the result of
// division will be unsigned too, and will be a very large number
// if height was negative!
height = height / (int)count;
// Use max() so that we don't set a negative height when there is
// not enough room.
2018-10-23 11:33:06 +00:00
height = std::max( (int)TrackInfo::MinimumTrackHeight(), height );
for (auto t : range)
TrackView::Get( *t ).SetHeight(height);
2018-10-23 11:33:06 +00:00
}
}
namespace ViewActions {
2018-10-23 11:33:06 +00:00
// Menu handler functions
struct Handler final
: CommandHandlerObject // MUST be the first base class!
, ClientData::Base
{
2018-10-23 11:33:06 +00:00
void OnZoomIn(const CommandContext &context)
{
auto &project = context.project;
auto &trackPanel = TrackPanel::Get( project );
auto &window = ProjectWindow::Get( project );
window.ZoomInByFactor( 2.0 );
trackPanel.Refresh(false);
2018-10-23 11:33:06 +00:00
}
void OnZoomNormal(const CommandContext &context)
{
auto &project = context.project;
auto &trackPanel = TrackPanel::Get( project );
auto &window = ProjectWindow::Get( project );
2018-10-23 11:33:06 +00:00
window.Zoom(ZoomInfo::GetDefaultZoom());
trackPanel.Refresh(false);
2018-10-23 11:33:06 +00:00
}
void OnZoomOut(const CommandContext &context)
{
auto &project = context.project;
auto &window = ProjectWindow::Get( project );
window.ZoomOutByFactor( 1 /2.0 );
2018-10-23 11:33:06 +00:00
}
void OnZoomSel(const CommandContext &context)
{
auto &project = context.project;
auto &selectedRegion = ViewInfo::Get( project ).selectedRegion;
auto &window = ProjectWindow::Get( project );
2018-10-23 11:33:06 +00:00
window.Zoom( GetZoomOfSelection( project ) );
window.TP_ScrollWindow(selectedRegion.t0());
2018-10-23 11:33:06 +00:00
}
void OnZoomToggle(const CommandContext &context)
{
auto &project = context.project;
auto &viewInfo = ViewInfo::Get( project );
auto &trackPanel = TrackPanel::Get( project );
auto &window = ProjectWindow::Get( project );
2018-10-23 11:33:06 +00:00
// const double origLeft = viewInfo.h;
2019-06-21 16:14:46 +00:00
// const double origWidth = viewInfo.GetScreenEndTime() - origLeft;
2018-10-23 11:33:06 +00:00
// Choose the zoom that is most different to the current zoom.
2018-10-27 23:47:48 +00:00
double Zoom1 = GetZoomOfPreset( project, TracksPrefs::Zoom1Choice() );
double Zoom2 = GetZoomOfPreset( project, TracksPrefs::Zoom2Choice() );
2018-10-23 11:33:06 +00:00
double Z = viewInfo.GetZoom();// Current Zoom.
double ChosenZoom =
fabs(log(Zoom1 / Z)) > fabs(log( Z / Zoom2)) ? Zoom1:Zoom2;
window.Zoom(ChosenZoom);
trackPanel.Refresh(false);
2018-10-23 11:33:06 +00:00
// const double newWidth = GetScreenEndTime() - viewInfo.h;
// const double newh = origLeft + (origWidth - newWidth) / 2;
// TP_ScrollWindow(newh);
}
void OnZoomFit(const CommandContext &context)
{
auto &project = context.project;
auto &window = ProjectWindow::Get( project );
window.DoZoomFit();
2018-10-23 11:33:06 +00:00
}
void OnZoomFitV(const CommandContext &context)
{
auto &project = context.project;
auto &window = ProjectWindow::Get( project );
2018-10-23 11:33:06 +00:00
DoZoomFitV(project);
window.GetVerticalScrollBar().SetThumbPosition(0);
ProjectHistory::Get( project ).ModifyState(true);
2018-10-23 11:33:06 +00:00
}
void OnAdvancedVZoom(const CommandContext &context)
{
auto &project = context.project;
auto &commandManager = CommandManager::Get( project );
bool checked = !gPrefs->Read(wxT("/GUI/VerticalZooming"), 0L);
gPrefs->Write(wxT("/GUI/VerticalZooming"), checked);
gPrefs->Flush();
commandManager.Check(wxT("AdvancedVZoom"), checked);
MenuCreator::RebuildAllMenuBars();
}
2018-10-23 11:33:06 +00:00
void OnCollapseAllTracks(const CommandContext &context)
{
auto &project = context.project;
auto &tracks = TrackList::Get( project );
auto &window = ProjectWindow::Get( project );
2018-10-23 11:33:06 +00:00
for (auto t : tracks.Any())
2019-06-18 15:29:38 +00:00
TrackView::Get( *t ).SetMinimized(true);
2018-10-23 11:33:06 +00:00
ProjectHistory::Get( project ).ModifyState(true);
2018-10-23 11:33:06 +00:00
}
void OnExpandAllTracks(const CommandContext &context)
{
auto &project = context.project;
auto &tracks = TrackList::Get( project );
auto &window = ProjectWindow::Get( project );
2018-10-23 11:33:06 +00:00
for (auto t : tracks.Any())
2019-06-18 15:29:38 +00:00
TrackView::Get( *t ).SetMinimized(false);
2018-10-23 11:33:06 +00:00
ProjectHistory::Get( project ).ModifyState(true);
2018-10-23 11:33:06 +00:00
}
void OnGoSelStart(const CommandContext &context)
{
auto &project = context.project;
auto &viewInfo = ViewInfo::Get( project );
2018-10-23 11:33:06 +00:00
auto &selectedRegion = viewInfo.selectedRegion;
auto &window = ProjectWindow::Get( project );
2018-10-23 11:33:06 +00:00
if (selectedRegion.isPoint())
return;
window.TP_ScrollWindow(
2019-06-21 16:14:46 +00:00
selectedRegion.t0() - ((viewInfo.GetScreenEndTime() - viewInfo.h) / 2));
2018-10-23 11:33:06 +00:00
}
void OnGoSelEnd(const CommandContext &context)
{
auto &project = context.project;
auto &viewInfo = ViewInfo::Get( project );
2018-10-23 11:33:06 +00:00
auto &selectedRegion = viewInfo.selectedRegion;
auto &window = ProjectWindow::Get( project );
2018-10-23 11:33:06 +00:00
if (selectedRegion.isPoint())
return;
window.TP_ScrollWindow(
2019-06-21 16:14:46 +00:00
selectedRegion.t1() - ((viewInfo.GetScreenEndTime() - viewInfo.h) / 2));
2018-10-23 11:33:06 +00:00
}
void OnShowExtraMenus(const CommandContext &context)
{
auto &project = context.project;
auto &commandManager = CommandManager::Get( project );
2018-10-23 11:33:06 +00:00
bool checked = !gPrefs->Read(wxT("/GUI/ShowExtraMenus"), 0L);
gPrefs->Write(wxT("/GUI/ShowExtraMenus"), checked);
gPrefs->Flush();
commandManager.Check(wxT("ShowExtraMenus"), checked);
MenuCreator::RebuildAllMenuBars();
2018-10-23 11:33:06 +00:00
}
void OnShowClipping(const CommandContext &context)
{
auto &project = context.project;
auto &commandManager = CommandManager::Get( project );
auto &trackPanel = TrackPanel::Get( project );
2018-10-23 11:33:06 +00:00
bool checked = !gPrefs->Read(wxT("/GUI/ShowClipping"), 0L);
gPrefs->Write(wxT("/GUI/ShowClipping"), checked);
gPrefs->Flush();
commandManager.Check(wxT("ShowClipping"), checked);
wxTheApp->AddPendingEvent(wxCommandEvent{
EVT_PREFS_UPDATE, ShowClippingPrefsID() });
trackPanel.Refresh(false);
2018-10-23 11:33:06 +00:00
}
void OnShowNameOverlay(const CommandContext &context)
{
auto &project = context.project;
auto &commandManager = CommandManager::Get( project );
auto &trackPanel = TrackPanel::Get( project );
bool checked = !gPrefs->Read(wxT("/GUI/ShowTrackNameInWaveform"), 0L);
gPrefs->Write(wxT("/GUI/ShowTrackNameInWaveform"), checked);
gPrefs->Flush();
commandManager.Check(wxT("ShowTrackNameInWaveform"), checked);
wxTheApp->AddPendingEvent(wxCommandEvent{
EVT_PREFS_UPDATE, ShowTrackNameInWaveformPrefsID() });
trackPanel.Refresh(false);
}
2018-10-23 11:33:06 +00:00
#if defined(EXPERIMENTAL_EFFECTS_RACK)
void OnShowEffectsRack(const CommandContext &context )
2018-10-23 11:33:06 +00:00
{
auto &rack = EffectRack::Get( context.project );
rack.Show( !rack.IsShown() );
2018-10-23 11:33:06 +00:00
}
#endif
// Not a menu item, but a listener for events
void OnUndoPushed( wxCommandEvent &evt )
{
evt.Skip();
const auto &settings = ProjectSettings::Get( mProject );
if (settings.GetTracksFitVerticallyZoomed())
DoZoomFitV( mProject );
}
Handler( AudacityProject &project )
: mProject{ project }
{
mProject.Bind( EVT_UNDO_PUSHED, &Handler::OnUndoPushed, this );
}
~Handler()
{
mProject.Unbind( EVT_UNDO_PUSHED, &Handler::OnUndoPushed, this );
}
Handler( const Handler & ) PROHIBITED;
Handler &operator=( const Handler & ) PROHIBITED;
AudacityProject &mProject;
2018-10-23 11:33:06 +00:00
}; // struct Handler
} // namespace
// Handler needs a back-reference to the project, so needs a factory registered
// with AudacityProject.
static const AudacityProject::AttachedObjects::RegisteredFactory key{
[]( AudacityProject &project ) {
return std::make_unique< ViewActions::Handler >( project ); } };
static CommandHandlerObject &findCommandHandler(AudacityProject &project) {
return project.AttachedObjects::Get< ViewActions::Handler >( key );
2018-10-23 11:33:06 +00:00
};
// Menu definitions
#define FN(X) (& ViewActions::Handler :: X)
2018-10-23 11:33:06 +00:00
// Under /MenuBar
namespace {
using namespace MenuTable;
BaseItemSharedPtr ViewMenu()
2018-10-23 11:33:06 +00:00
{
using Options = CommandManager::Options;
static BaseItemSharedPtr menu{
( FinderScope{ findCommandHandler },
Menu( wxT("View"), XXO("&View"),
Section( "Basic",
Menu( wxT("Zoom"), XXO("&Zoom"),
2020-01-30 16:01:07 +00:00
Section( "",
Command( wxT("ZoomIn"), XXO("Zoom &In"), FN(OnZoomIn),
ZoomInAvailableFlag(), wxT("Ctrl+1") ),
Command( wxT("ZoomNormal"), XXO("Zoom &Normal"), FN(OnZoomNormal),
TracksExistFlag(), wxT("Ctrl+2") ),
Command( wxT("ZoomOut"), XXO("Zoom &Out"), FN(OnZoomOut),
ZoomOutAvailableFlag(), wxT("Ctrl+3") ),
Command( wxT("ZoomSel"), XXO("&Zoom to Selection"), FN(OnZoomSel),
TimeSelectedFlag(), wxT("Ctrl+E") ),
Command( wxT("ZoomToggle"), XXO("Zoom &Toggle"), FN(OnZoomToggle),
TracksExistFlag(), wxT("Shift+Z") )
),
Section( "",
Command( wxT("AdvancedVZoom"), XXO("Advanced &Vertical Zooming"),
FN(OnAdvancedVZoom), AlwaysEnabledFlag,
Options{}.CheckTest( wxT("/GUI/VerticalZooming"), false ) )
)
),
Menu( wxT("TrackSize"), XXO("T&rack Size"),
2020-01-30 16:01:07 +00:00
Command( wxT("FitInWindow"), XXO("&Fit to Width"), FN(OnZoomFit),
TracksExistFlag(), wxT("Ctrl+F") ),
Command( wxT("FitV"), XXO("Fit to &Height"), FN(OnZoomFitV),
TracksExistFlag(), wxT("Ctrl+Shift+F") ),
Command( wxT("CollapseAllTracks"), XXO("&Collapse All Tracks"),
FN(OnCollapseAllTracks), TracksExistFlag(), wxT("Ctrl+Shift+C") ),
Command( wxT("ExpandAllTracks"), XXO("E&xpand Collapsed Tracks"),
FN(OnExpandAllTracks), TracksExistFlag(), wxT("Ctrl+Shift+X") )
),
Menu( wxT("SkipTo"), XXO("Sk&ip to"),
2020-01-30 16:01:07 +00:00
Command( wxT("SkipSelStart"), XXO("Selection Sta&rt"),
FN(OnGoSelStart), TimeSelectedFlag(),
Options{ wxT("Ctrl+["), XO("Skip to Selection Start") } ),
Command( wxT("SkipSelEnd"), XXO("Selection En&d"), FN(OnGoSelEnd),
TimeSelectedFlag(),
Options{ wxT("Ctrl+]"), XO("Skip to Selection End") } )
)
2018-10-23 11:33:06 +00:00
),
Section( "Windows" ),
2018-10-23 11:33:06 +00:00
Section( "Other",
2020-01-30 16:01:07 +00:00
Command( wxT("ShowExtraMenus"), XXO("&Extra Menus (on/off)"),
FN(OnShowExtraMenus), AlwaysEnabledFlag,
Options{}.CheckTest( wxT("/GUI/ShowExtraMenus"), false ) ),
Command( wxT("ShowTrackNameInWaveform"), XXO("Track &Name (on/off)"),
FN(OnShowNameOverlay), AlwaysEnabledFlag,
Options{}.CheckTest( wxT("/GUI/ShowTrackNameInWaveform"), false ) ),
2020-01-30 16:01:07 +00:00
Command( wxT("ShowClipping"), XXO("&Show Clipping (on/off)"),
FN(OnShowClipping), AlwaysEnabledFlag,
Options{}.CheckTest( wxT("/GUI/ShowClipping"), false ) )
#if defined(EXPERIMENTAL_EFFECTS_RACK)
,
Command( wxT("ShowEffectsRack"), XXO("Show Effects Rack"),
FN(OnShowEffectsRack), AlwaysEnabledFlag,
Options{}.CheckTest( [](AudacityProject &project){
auto &rack = EffectRack::Get( project );
return rack.IsShown(); } ) )
2020-01-30 16:01:07 +00:00
#endif
)
) ) };
return menu;
2018-10-23 11:33:06 +00:00
}
AttachedItem sAttachment1{
wxT(""),
Shared( ViewMenu() )
};
}
2018-10-23 11:33:06 +00:00
#undef FN