mirror of
https://github.com/cookiengineer/audacity
synced 2025-08-10 00:51:13 +02:00
Move details of mouse wheel handling into ProjectWindow.cpp ...
... to break some dependency cycles. Install a callback at initialization time. This frees CommonTrackPanelCell from cycles, which is important because it is a base class of Track
This commit is contained in:
parent
7b09225bf7
commit
d4b44d16f1
@ -18,7 +18,9 @@ Paul Licameli split from AudacityProject.cpp
|
||||
#include "Menus.h"
|
||||
#include "Project.h"
|
||||
#include "ProjectAudioIO.h"
|
||||
#include "RefreshCode.h"
|
||||
#include "TrackPanel.h"
|
||||
#include "TrackPanelMouseEvent.h"
|
||||
#include "ViewInfo.h"
|
||||
#include "WaveClip.h"
|
||||
#include "WaveTrack.h"
|
||||
@ -353,6 +355,151 @@ BEGIN_EVENT_TABLE(ScrollBar, wxScrollBar)
|
||||
EVT_SET_FOCUS(ScrollBar::OnSetFocus)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
// Common mouse wheel handling in track panel cells, moved here to avoid
|
||||
// compilation dependencies on Track, TrackPanel, and Scrubbing at low levels
|
||||
// which made cycles
|
||||
static struct MouseWheelHandler {
|
||||
|
||||
MouseWheelHandler()
|
||||
{
|
||||
CommonTrackPanelCell::InstallMouseWheelHook( *this );
|
||||
}
|
||||
|
||||
// Need a bit of memory from one call to the next
|
||||
mutable double mVertScrollRemainder = 0.0;
|
||||
|
||||
unsigned operator()
|
||||
( const TrackPanelMouseEvent &evt, AudacityProject *pProject ) const
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
|
||||
if ( TrackList::Get( *pProject ).empty() )
|
||||
// Scrolling and Zoom in and out commands are disabled when there are no tracks.
|
||||
// This should be disabled too for consistency. Otherwise
|
||||
// you do see changes in the time ruler.
|
||||
return Cancelled;
|
||||
|
||||
unsigned result = RefreshAll;
|
||||
const wxMouseEvent &event = evt.event;
|
||||
auto &viewInfo = ViewInfo::Get( *pProject );
|
||||
Scrubber &scrubber = Scrubber::Get( *pProject );
|
||||
auto &window = ProjectWindow::Get( *pProject );
|
||||
const auto steps = evt.steps;
|
||||
|
||||
if (event.ShiftDown()
|
||||
// Don't pan during smooth scrolling. That would conflict with keeping
|
||||
// the play indicator centered.
|
||||
&& !scrubber.IsScrollScrubbing()
|
||||
)
|
||||
{
|
||||
// MM: Scroll left/right when used with Shift key down
|
||||
window.TP_ScrollWindow(
|
||||
viewInfo.OffsetTimeByPixels(
|
||||
viewInfo.PositionToTime(0), 50.0 * -steps));
|
||||
}
|
||||
else if (event.CmdDown())
|
||||
{
|
||||
#if 0
|
||||
// JKC: Alternative scroll wheel zooming code
|
||||
// using AudacityProject zooming, which is smarter,
|
||||
// it keeps selections on screen and centred if it can,
|
||||
// also this ensures mousewheel and zoom buttons give same result.
|
||||
double ZoomFactor = pow(2.0, steps);
|
||||
AudacityProject *p = GetProject();
|
||||
if( steps > 0 )
|
||||
p->ZoomInByFactor( ZoomFactor );
|
||||
else
|
||||
p->ZoomOutByFactor( ZoomFactor );
|
||||
#endif
|
||||
// MM: Zoom in/out when used with Control key down
|
||||
// We're converting pixel positions to times,
|
||||
// counting pixels from the left edge of the track.
|
||||
auto &trackPanel = TrackPanel::Get( *pProject );
|
||||
int trackLeftEdge = trackPanel.GetLeftOffset();
|
||||
|
||||
// Time corresponding to mouse position
|
||||
wxCoord xx;
|
||||
double center_h;
|
||||
double mouse_h = viewInfo.PositionToTime(event.m_x, trackLeftEdge);
|
||||
|
||||
// Scrubbing? Expand or contract about the center, ignoring mouse position
|
||||
if (scrubber.IsScrollScrubbing())
|
||||
center_h = viewInfo.h +
|
||||
(trackPanel.GetScreenEndTime() - viewInfo.h) / 2.0;
|
||||
// Zooming out? Focus on mouse.
|
||||
else if( steps <= 0 )
|
||||
center_h = mouse_h;
|
||||
// No Selection? Focus on mouse.
|
||||
else if((viewInfo.selectedRegion.t1() - viewInfo.selectedRegion.t0() ) < 0.00001 )
|
||||
center_h = mouse_h;
|
||||
// Before Selection? Focus on left
|
||||
else if( mouse_h < viewInfo.selectedRegion.t0() )
|
||||
center_h = viewInfo.selectedRegion.t0();
|
||||
// After Selection? Focus on right
|
||||
else if( mouse_h > viewInfo.selectedRegion.t1() )
|
||||
center_h = viewInfo.selectedRegion.t1();
|
||||
// Inside Selection? Focus on mouse
|
||||
else
|
||||
center_h = mouse_h;
|
||||
|
||||
xx = viewInfo.TimeToPosition(center_h, trackLeftEdge);
|
||||
|
||||
// Time corresponding to last (most far right) audio.
|
||||
double audioEndTime = TrackList::Get( *pProject ).GetEndTime();
|
||||
|
||||
// Disabled this code to fix Bug 1923 (tricky to wheel-zoom right of waveform).
|
||||
#if 0
|
||||
// When zooming in in empty space, it's easy to 'lose' the waveform.
|
||||
// This prevents it.
|
||||
// IF zooming in
|
||||
if (steps > 0)
|
||||
{
|
||||
// IF mouse is to right of audio
|
||||
if (center_h > audioEndTime)
|
||||
// Zooming brings far right of audio to mouse.
|
||||
center_h = audioEndTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
wxCoord xTrackEnd = viewInfo.TimeToPosition( audioEndTime );
|
||||
viewInfo.ZoomBy(pow(2.0, steps));
|
||||
|
||||
double new_center_h = viewInfo.PositionToTime(xx, trackLeftEdge);
|
||||
viewInfo.h += (center_h - new_center_h);
|
||||
|
||||
// If wave has gone off screen, bring it back.
|
||||
// This means that the end of the track stays where it was.
|
||||
if( viewInfo.h > audioEndTime )
|
||||
viewInfo.h += audioEndTime - viewInfo.PositionToTime( xTrackEnd );
|
||||
|
||||
|
||||
result |= FixScrollbars;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL
|
||||
if (scrubber.IsScrubbing()) {
|
||||
scrubber.HandleScrollWheel(steps);
|
||||
evt.event.Skip(false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// MM: Scroll up/down when used without modifier keys
|
||||
double lines = steps * 4 + mVertScrollRemainder;
|
||||
mVertScrollRemainder = lines - floor(lines);
|
||||
lines = floor(lines);
|
||||
auto didSomething = window.TP_ScrollUpDown((int)-lines);
|
||||
if (!didSomething)
|
||||
result |= Cancelled;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} sMouseWheelHandler;
|
||||
|
||||
AudacityProject::AttachedWindows::RegisteredFactory sProjectWindowKey{
|
||||
[]( AudacityProject &parent ) -> wxWeakRef< wxWindow > {
|
||||
wxRect wndRect;
|
||||
|
@ -8,19 +8,30 @@ Paul Licameli split from TrackPanel.cpp
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "../../Audacity.h"
|
||||
#include "CommonTrackPanelCell.h"
|
||||
|
||||
#include "../../Experimental.h"
|
||||
#include <wx/cursor.h>
|
||||
|
||||
#include "Scrubbing.h"
|
||||
|
||||
#include "../../ProjectWindow.h"
|
||||
#include "../../HitTestResult.h"
|
||||
#include "../../RefreshCode.h"
|
||||
#include "../../Track.h"
|
||||
#include "../../TrackPanel.h"
|
||||
#include "../../TrackPanelMouseEvent.h"
|
||||
#include "../../ViewInfo.h"
|
||||
|
||||
namespace {
|
||||
CommonTrackPanelCell::Hook &GetHook()
|
||||
{
|
||||
static CommonTrackPanelCell::Hook theHook;
|
||||
return theHook;
|
||||
}
|
||||
}
|
||||
|
||||
auto CommonTrackPanelCell::InstallMouseWheelHook( const Hook &hook )
|
||||
-> Hook
|
||||
{
|
||||
auto &theHook = GetHook();
|
||||
auto result = theHook;
|
||||
theHook = hook;
|
||||
return result;
|
||||
}
|
||||
|
||||
CommonTrackPanelCell::~CommonTrackPanelCell()
|
||||
{
|
||||
@ -36,129 +47,6 @@ HitTestPreview CommonTrackPanelCell::DefaultPreview
|
||||
unsigned CommonTrackPanelCell::HandleWheelRotation
|
||||
(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
{
|
||||
using namespace RefreshCode;
|
||||
|
||||
if ( TrackList::Get( *pProject ).empty() )
|
||||
// Scrolling and Zoom in and out commands are disabled when there are no tracks.
|
||||
// This should be disabled too for consistency. Otherwise
|
||||
// you do see changes in the time ruler.
|
||||
return Cancelled;
|
||||
|
||||
unsigned result = RefreshAll;
|
||||
const wxMouseEvent &event = evt.event;
|
||||
auto &viewInfo = ViewInfo::Get( *pProject );
|
||||
Scrubber &scrubber = Scrubber::Get( *pProject );
|
||||
auto &window = ProjectWindow::Get( *pProject );
|
||||
const auto steps = evt.steps;
|
||||
|
||||
if (event.ShiftDown()
|
||||
// Don't pan during smooth scrolling. That would conflict with keeping
|
||||
// the play indicator centered.
|
||||
&& !scrubber.IsScrollScrubbing()
|
||||
)
|
||||
{
|
||||
// MM: Scroll left/right when used with Shift key down
|
||||
window.TP_ScrollWindow(
|
||||
viewInfo.OffsetTimeByPixels(
|
||||
viewInfo.PositionToTime(0), 50.0 * -steps));
|
||||
}
|
||||
else if (event.CmdDown())
|
||||
{
|
||||
#if 0
|
||||
// JKC: Alternative scroll wheel zooming code
|
||||
// using AudacityProject zooming, which is smarter,
|
||||
// it keeps selections on screen and centred if it can,
|
||||
// also this ensures mousewheel and zoom buttons give same result.
|
||||
double ZoomFactor = pow(2.0, steps);
|
||||
AudacityProject *p = GetProject();
|
||||
if( steps > 0 )
|
||||
p->ZoomInByFactor( ZoomFactor );
|
||||
else
|
||||
p->ZoomOutByFactor( ZoomFactor );
|
||||
#endif
|
||||
// MM: Zoom in/out when used with Control key down
|
||||
// We're converting pixel positions to times,
|
||||
// counting pixels from the left edge of the track.
|
||||
auto &trackPanel = TrackPanel::Get( *pProject );
|
||||
int trackLeftEdge = trackPanel.GetLeftOffset();
|
||||
|
||||
// Time corresponding to mouse position
|
||||
wxCoord xx;
|
||||
double center_h;
|
||||
double mouse_h = viewInfo.PositionToTime(event.m_x, trackLeftEdge);
|
||||
|
||||
// Scrubbing? Expand or contract about the center, ignoring mouse position
|
||||
if (scrubber.IsScrollScrubbing())
|
||||
center_h = viewInfo.h +
|
||||
(trackPanel.GetScreenEndTime() - viewInfo.h) / 2.0;
|
||||
// Zooming out? Focus on mouse.
|
||||
else if( steps <= 0 )
|
||||
center_h = mouse_h;
|
||||
// No Selection? Focus on mouse.
|
||||
else if((viewInfo.selectedRegion.t1() - viewInfo.selectedRegion.t0() ) < 0.00001 )
|
||||
center_h = mouse_h;
|
||||
// Before Selection? Focus on left
|
||||
else if( mouse_h < viewInfo.selectedRegion.t0() )
|
||||
center_h = viewInfo.selectedRegion.t0();
|
||||
// After Selection? Focus on right
|
||||
else if( mouse_h > viewInfo.selectedRegion.t1() )
|
||||
center_h = viewInfo.selectedRegion.t1();
|
||||
// Inside Selection? Focus on mouse
|
||||
else
|
||||
center_h = mouse_h;
|
||||
|
||||
xx = viewInfo.TimeToPosition(center_h, trackLeftEdge);
|
||||
|
||||
// Time corresponding to last (most far right) audio.
|
||||
double audioEndTime = TrackList::Get( *pProject ).GetEndTime();
|
||||
|
||||
// Disabled this code to fix Bug 1923 (tricky to wheel-zoom right of waveform).
|
||||
#if 0
|
||||
// When zooming in in empty space, it's easy to 'lose' the waveform.
|
||||
// This prevents it.
|
||||
// IF zooming in
|
||||
if (steps > 0)
|
||||
{
|
||||
// IF mouse is to right of audio
|
||||
if (center_h > audioEndTime)
|
||||
// Zooming brings far right of audio to mouse.
|
||||
center_h = audioEndTime;
|
||||
}
|
||||
#endif
|
||||
|
||||
wxCoord xTrackEnd = viewInfo.TimeToPosition( audioEndTime );
|
||||
viewInfo.ZoomBy(pow(2.0, steps));
|
||||
|
||||
double new_center_h = viewInfo.PositionToTime(xx, trackLeftEdge);
|
||||
viewInfo.h += (center_h - new_center_h);
|
||||
|
||||
// If wave has gone off screen, bring it back.
|
||||
// This means that the end of the track stays where it was.
|
||||
if( viewInfo.h > audioEndTime )
|
||||
viewInfo.h += audioEndTime - viewInfo.PositionToTime( xTrackEnd );
|
||||
|
||||
|
||||
result |= FixScrollbars;
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL
|
||||
if (scrubber.IsScrubbing()) {
|
||||
scrubber.HandleScrollWheel(steps);
|
||||
evt.event.Skip(false);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// MM: Scroll up/down when used without modifier keys
|
||||
double lines = steps * 4 + mVertScrollRemainder;
|
||||
mVertScrollRemainder = lines - floor(lines);
|
||||
lines = floor(lines);
|
||||
auto didSomething = window.TP_ScrollUpDown((int)-lines);
|
||||
if (!didSomething)
|
||||
result |= Cancelled;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
auto hook = GetHook();
|
||||
return hook ? hook( evt, pProject ) : RefreshCode::Cancelled;
|
||||
}
|
||||
|
@ -12,7 +12,9 @@ Paul Licameli split from TrackPanel.cpp
|
||||
#define __AUDACITY_COMMON_TRACK_PANEL_CELL__
|
||||
|
||||
#include "../../TrackPanelCell.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <functional>
|
||||
|
||||
class Track;
|
||||
|
||||
@ -20,8 +22,14 @@ class AUDACITY_DLL_API CommonTrackPanelCell /* not final */
|
||||
: public TrackPanelCell
|
||||
{
|
||||
public:
|
||||
// Type of function to dispatch mouse wheel events
|
||||
using Hook = std::function<
|
||||
unsigned(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
|
||||
>;
|
||||
// Install a dispatcher function, returning the previous function
|
||||
static Hook InstallMouseWheelHook( const Hook &hook );
|
||||
|
||||
CommonTrackPanelCell()
|
||||
: mVertScrollRemainder(0.0)
|
||||
{}
|
||||
|
||||
virtual ~CommonTrackPanelCell() = 0;
|
||||
@ -41,8 +49,6 @@ protected:
|
||||
(const TrackPanelMouseEvent &event,
|
||||
AudacityProject *pProject) override;
|
||||
|
||||
private:
|
||||
double mVertScrollRemainder;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user