mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-17 16:40:07 +02:00
Move class CellularPanel into its own files
This commit is contained in:
parent
7f84e71324
commit
f6609e5ffb
@ -1206,6 +1206,7 @@
|
|||||||
5E07842E1DEE6B8600CA76EA /* FileException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842C1DEE6B8600CA76EA /* FileException.cpp */; };
|
5E07842E1DEE6B8600CA76EA /* FileException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842C1DEE6B8600CA76EA /* FileException.cpp */; };
|
||||||
5E0784311DF1E4F400CA76EA /* UserException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842F1DF1E4F400CA76EA /* UserException.cpp */; };
|
5E0784311DF1E4F400CA76EA /* UserException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E07842F1DF1E4F400CA76EA /* UserException.cpp */; };
|
||||||
5E0A0E311D23019A00CD2567 /* MenusMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E0A0E301D23019A00CD2567 /* MenusMac.cpp */; };
|
5E0A0E311D23019A00CD2567 /* MenusMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E0A0E301D23019A00CD2567 /* MenusMac.cpp */; };
|
||||||
|
5E0A1CDD20E95FF7001AAF8D /* CellularPanel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E0A1CDB20E95FF7001AAF8D /* CellularPanel.cpp */; };
|
||||||
5E10D9061EC8F81300B3AC57 /* PlayableTrackButtonHandles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E10D9041EC8F81300B3AC57 /* PlayableTrackButtonHandles.cpp */; };
|
5E10D9061EC8F81300B3AC57 /* PlayableTrackButtonHandles.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E10D9041EC8F81300B3AC57 /* PlayableTrackButtonHandles.cpp */; };
|
||||||
5E15123D1DB000C000702E29 /* UIHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E15123B1DB000C000702E29 /* UIHandle.cpp */; };
|
5E15123D1DB000C000702E29 /* UIHandle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E15123B1DB000C000702E29 /* UIHandle.cpp */; };
|
||||||
5E15125A1DB000DC00702E29 /* LabelTrackControls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E1512401DB000DC00702E29 /* LabelTrackControls.cpp */; };
|
5E15125A1DB000DC00702E29 /* LabelTrackControls.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5E1512401DB000DC00702E29 /* LabelTrackControls.cpp */; };
|
||||||
@ -3053,6 +3054,8 @@
|
|||||||
5E07842F1DF1E4F400CA76EA /* UserException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserException.cpp; sourceTree = "<group>"; };
|
5E07842F1DF1E4F400CA76EA /* UserException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserException.cpp; sourceTree = "<group>"; };
|
||||||
5E0784301DF1E4F400CA76EA /* UserException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserException.h; sourceTree = "<group>"; };
|
5E0784301DF1E4F400CA76EA /* UserException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserException.h; sourceTree = "<group>"; };
|
||||||
5E0A0E301D23019A00CD2567 /* MenusMac.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = MenusMac.cpp; sourceTree = "<group>"; };
|
5E0A0E301D23019A00CD2567 /* MenusMac.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = MenusMac.cpp; sourceTree = "<group>"; };
|
||||||
|
5E0A1CDB20E95FF7001AAF8D /* CellularPanel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CellularPanel.cpp; sourceTree = "<group>"; };
|
||||||
|
5E0A1CDC20E95FF7001AAF8D /* CellularPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CellularPanel.h; sourceTree = "<group>"; };
|
||||||
5E10D9041EC8F81300B3AC57 /* PlayableTrackButtonHandles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlayableTrackButtonHandles.cpp; sourceTree = "<group>"; };
|
5E10D9041EC8F81300B3AC57 /* PlayableTrackButtonHandles.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlayableTrackButtonHandles.cpp; sourceTree = "<group>"; };
|
||||||
5E10D9051EC8F81300B3AC57 /* PlayableTrackButtonHandles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayableTrackButtonHandles.h; sourceTree = "<group>"; };
|
5E10D9051EC8F81300B3AC57 /* PlayableTrackButtonHandles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlayableTrackButtonHandles.h; sourceTree = "<group>"; };
|
||||||
5E1512381DB000C000702E29 /* HitTestResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HitTestResult.h; sourceTree = "<group>"; };
|
5E1512381DB000C000702E29 /* HitTestResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HitTestResult.h; sourceTree = "<group>"; };
|
||||||
@ -4053,6 +4056,7 @@
|
|||||||
1790AFD809883BFD008A330A /* BatchProcessDialog.cpp */,
|
1790AFD809883BFD008A330A /* BatchProcessDialog.cpp */,
|
||||||
1790AFDA09883BFD008A330A /* Benchmark.cpp */,
|
1790AFDA09883BFD008A330A /* Benchmark.cpp */,
|
||||||
1790AFE809883BFD008A330A /* BlockFile.cpp */,
|
1790AFE809883BFD008A330A /* BlockFile.cpp */,
|
||||||
|
5E0A1CDB20E95FF7001AAF8D /* CellularPanel.cpp */,
|
||||||
1790AFF409883BFD008A330A /* CrossFade.cpp */,
|
1790AFF409883BFD008A330A /* CrossFade.cpp */,
|
||||||
2849B4600A7444BE00ECF12D /* Dependencies.cpp */,
|
2849B4600A7444BE00ECF12D /* Dependencies.cpp */,
|
||||||
28D000A31A32920C00367B21 /* DeviceChange.cpp */,
|
28D000A31A32920C00367B21 /* DeviceChange.cpp */,
|
||||||
@ -4147,6 +4151,7 @@
|
|||||||
1790AFD909883BFD008A330A /* BatchProcessDialog.h */,
|
1790AFD909883BFD008A330A /* BatchProcessDialog.h */,
|
||||||
1790AFDB09883BFD008A330A /* Benchmark.h */,
|
1790AFDB09883BFD008A330A /* Benchmark.h */,
|
||||||
1790AFE909883BFD008A330A /* BlockFile.h */,
|
1790AFE909883BFD008A330A /* BlockFile.h */,
|
||||||
|
5E0A1CDC20E95FF7001AAF8D /* CellularPanel.h */,
|
||||||
1790AFF009883BFD008A330A /* configtemplate.h */,
|
1790AFF009883BFD008A330A /* configtemplate.h */,
|
||||||
1790AFF509883BFD008A330A /* CrossFade.h */,
|
1790AFF509883BFD008A330A /* CrossFade.h */,
|
||||||
2849B4610A7444BE00ECF12D /* Dependencies.h */,
|
2849B4610A7444BE00ECF12D /* Dependencies.h */,
|
||||||
@ -7729,6 +7734,7 @@
|
|||||||
1790B11E09883BFD008A330A /* BatchCommands.cpp in Sources */,
|
1790B11E09883BFD008A330A /* BatchCommands.cpp in Sources */,
|
||||||
5ED1D0B11CDE560C00471E3C /* BackedPanel.cpp in Sources */,
|
5ED1D0B11CDE560C00471E3C /* BackedPanel.cpp in Sources */,
|
||||||
1790B11F09883BFD008A330A /* BatchProcessDialog.cpp in Sources */,
|
1790B11F09883BFD008A330A /* BatchProcessDialog.cpp in Sources */,
|
||||||
|
5E0A1CDD20E95FF7001AAF8D /* CellularPanel.cpp in Sources */,
|
||||||
1790B12009883BFD008A330A /* Benchmark.cpp in Sources */,
|
1790B12009883BFD008A330A /* Benchmark.cpp in Sources */,
|
||||||
1790B12109883BFD008A330A /* LegacyAliasBlockFile.cpp in Sources */,
|
1790B12109883BFD008A330A /* LegacyAliasBlockFile.cpp in Sources */,
|
||||||
1790B12209883BFD008A330A /* LegacyBlockFile.cpp in Sources */,
|
1790B12209883BFD008A330A /* LegacyBlockFile.cpp in Sources */,
|
||||||
|
784
src/CellularPanel.cpp
Normal file
784
src/CellularPanel.cpp
Normal file
@ -0,0 +1,784 @@
|
|||||||
|
/**********************************************************************
|
||||||
|
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
CellularPanel.cpp
|
||||||
|
|
||||||
|
Dominic Mazzoni
|
||||||
|
and lots of other contributors
|
||||||
|
|
||||||
|
Implements CellularPanel.
|
||||||
|
|
||||||
|
********************************************************************//*!
|
||||||
|
|
||||||
|
\class CellularPanel
|
||||||
|
\brief
|
||||||
|
|
||||||
|
Formerly part of TrackPanel, this abstract base class has no special knowledge
|
||||||
|
of Track objects and is intended for reuse with other windows.
|
||||||
|
|
||||||
|
Manages a division of a panel's area into disjoint rectangles, each with
|
||||||
|
an associated Cell object. Details of that partition and association, and
|
||||||
|
the choice of the cell with keyboard focus, are subclass responsibilities.
|
||||||
|
|
||||||
|
Handling of keyboard events is delegated to the focused cell. The cell under
|
||||||
|
the mouse position is queried for hit-test candidate objects, which handle
|
||||||
|
click-drag-release (and ESC key abort) sequences.
|
||||||
|
|
||||||
|
*//*****************************************************************/
|
||||||
|
|
||||||
|
#include "Audacity.h"
|
||||||
|
#include "CellularPanel.h"
|
||||||
|
#include "Project.h"
|
||||||
|
#include "UIHandle.h"
|
||||||
|
#include "TrackPanelMouseEvent.h"
|
||||||
|
#include "HitTestResult.h"
|
||||||
|
#include "RefreshCode.h"
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_EVENT_TABLE(CellularPanel, OverlayPanel)
|
||||||
|
EVT_MOUSE_EVENTS(CellularPanel::OnMouseEvent)
|
||||||
|
EVT_MOUSE_CAPTURE_LOST(CellularPanel::OnCaptureLost)
|
||||||
|
EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEY, CellularPanel::OnCaptureKey)
|
||||||
|
EVT_KEY_DOWN(CellularPanel::OnKeyDown)
|
||||||
|
EVT_KEY_UP(CellularPanel::OnKeyUp)
|
||||||
|
EVT_CHAR(CellularPanel::OnChar)
|
||||||
|
EVT_SET_FOCUS(CellularPanel::OnSetFocus)
|
||||||
|
EVT_KILL_FOCUS(CellularPanel::OnKillFocus)
|
||||||
|
EVT_CONTEXT_MENU(CellularPanel::OnContextMenu)
|
||||||
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
|
void CellularPanel::HandleInterruptedDrag()
|
||||||
|
{
|
||||||
|
if (mUIHandle && mUIHandle->StopsOnKeystroke() ) {
|
||||||
|
// The bogus id isn't used anywhere, but may help with debugging.
|
||||||
|
// as this is sending a bogus mouse up. The mouse button is still actually down
|
||||||
|
// and may go up again.
|
||||||
|
const int idBogusUp = 2;
|
||||||
|
wxMouseEvent evt { wxEVT_LEFT_UP };
|
||||||
|
evt.SetId( idBogusUp );
|
||||||
|
evt.SetPosition(this->ScreenToClient(::wxGetMousePosition()));
|
||||||
|
this->ProcessEvent(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::Uncapture(wxMouseState *pState)
|
||||||
|
{
|
||||||
|
auto state = ::wxGetMouseState();
|
||||||
|
if (!pState) {
|
||||||
|
// Remap the position
|
||||||
|
state.SetPosition(this->ScreenToClient(state.GetPosition()));
|
||||||
|
pState = &state;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasCapture())
|
||||||
|
ReleaseMouse();
|
||||||
|
HandleMotion( *pState );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CellularPanel::CancelDragging()
|
||||||
|
{
|
||||||
|
if (mUIHandle) {
|
||||||
|
// copy shared_ptr for safety, as in HandleClick
|
||||||
|
auto handle = mUIHandle;
|
||||||
|
// UIHANDLE CANCEL
|
||||||
|
UIHandle::Result refreshResult = handle->Cancel(GetProject());
|
||||||
|
auto pClickedCell = mpClickedCell.lock();
|
||||||
|
if (pClickedCell)
|
||||||
|
ProcessUIHandleResult(
|
||||||
|
pClickedCell.get(), {},
|
||||||
|
refreshResult | mMouseOverUpdateFlags );
|
||||||
|
mpClickedCell.reset();
|
||||||
|
mUIHandle.reset(), handle.reset(), ClearTargets();
|
||||||
|
Uncapture();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CellularPanel::HandleEscapeKey(bool down)
|
||||||
|
{
|
||||||
|
if (!down)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto target = Target();
|
||||||
|
if (target && target->HasEscape() && target->Escape()) {
|
||||||
|
HandleCursorForPresentMouseState(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUIHandle) {
|
||||||
|
CancelDragging();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ChangeTarget(true, false)) {
|
||||||
|
HandleCursorForPresentMouseState(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::UpdateMouseState(const wxMouseState &state)
|
||||||
|
{
|
||||||
|
mLastMouseState = state;
|
||||||
|
|
||||||
|
// Simulate a down button if none, so hit test routines can anticipate
|
||||||
|
// which button will be clicked
|
||||||
|
if (!state.ButtonIsDown(wxMOUSE_BTN_ANY)) {
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
if (state.RawControlDown())
|
||||||
|
// On Mac we can distinctly anticipate "right" click (as Control+click)
|
||||||
|
mLastMouseState.SetRightDown( true ),
|
||||||
|
mLastMouseState.SetLeftDown( false );
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
// Anticipate a left click by default
|
||||||
|
mLastMouseState.SetRightDown( false ),
|
||||||
|
mLastMouseState.SetLeftDown( true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::HandleModifierKey()
|
||||||
|
{
|
||||||
|
HandleCursorForPresentMouseState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::HandleCursorForPresentMouseState(bool doHit)
|
||||||
|
{
|
||||||
|
// Come here on modifier key or mouse button transitions,
|
||||||
|
// or on starting or stopping of play or record,
|
||||||
|
// or change of toolbar button,
|
||||||
|
// and change the cursor appropriately.
|
||||||
|
|
||||||
|
// Get the button and key states
|
||||||
|
auto state = ::wxGetMouseState();
|
||||||
|
// Remap the position
|
||||||
|
state.SetPosition(this->ScreenToClient(state.GetPosition()));
|
||||||
|
|
||||||
|
HandleMotion( state, doHit );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CellularPanel::HandleMotion( ) sets the cursor drawn at the mouse location,
|
||||||
|
/// and updates the status bar message.
|
||||||
|
/// We treat certain other changes of mouse button and key state as "motions"
|
||||||
|
/// too, and also starting and stopping of playback or recording, all of which
|
||||||
|
/// may cause the appropriate cursor and message to change.
|
||||||
|
/// As this procedure checks which region the mouse is over, it is
|
||||||
|
/// appropriate to establish the message in the status bar.
|
||||||
|
void CellularPanel::HandleMotion( wxMouseState &inState, bool doHit )
|
||||||
|
{
|
||||||
|
UpdateMouseState( inState );
|
||||||
|
|
||||||
|
const auto foundCell = FindCell( inState.m_x, inState.m_y );
|
||||||
|
auto &rect = foundCell.rect;
|
||||||
|
auto &pCell = foundCell.pCell;
|
||||||
|
const TrackPanelMouseState tpmState{ mLastMouseState, rect, pCell };
|
||||||
|
HandleMotion( tpmState, doHit );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::HandleMotion
|
||||||
|
( const TrackPanelMouseState &tpmState, bool doHit )
|
||||||
|
{
|
||||||
|
auto handle = mUIHandle;
|
||||||
|
|
||||||
|
auto newCell = tpmState.pCell;
|
||||||
|
|
||||||
|
wxString status{}, tooltip{};
|
||||||
|
wxCursor *pCursor{};
|
||||||
|
unsigned refreshCode = 0;
|
||||||
|
|
||||||
|
if ( ! doHit ) {
|
||||||
|
// Dragging or not
|
||||||
|
handle = Target();
|
||||||
|
|
||||||
|
// Assume cell does not change but target does
|
||||||
|
refreshCode = mMouseOverUpdateFlags;
|
||||||
|
mMouseOverUpdateFlags = 0;
|
||||||
|
}
|
||||||
|
else if ( !mUIHandle ) {
|
||||||
|
// Not yet dragging.
|
||||||
|
|
||||||
|
auto oldCell = mLastCell.lock();
|
||||||
|
|
||||||
|
unsigned updateFlags = mMouseOverUpdateFlags;
|
||||||
|
|
||||||
|
// First check whether crossing cell to cell
|
||||||
|
if ( newCell == oldCell )
|
||||||
|
oldCell.reset();
|
||||||
|
else {
|
||||||
|
// Forget old targets
|
||||||
|
ClearTargets();
|
||||||
|
// Re-draw any highlighting
|
||||||
|
if (oldCell) {
|
||||||
|
ProcessUIHandleResult(
|
||||||
|
oldCell.get(), oldCell.get(), updateFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto oldHandle = Target();
|
||||||
|
auto oldPosition = mTarget;
|
||||||
|
|
||||||
|
// Now do the
|
||||||
|
// UIHANDLE HIT TEST !
|
||||||
|
mTargets = newCell->HitTest(tpmState, GetProject());
|
||||||
|
|
||||||
|
mTarget = 0;
|
||||||
|
|
||||||
|
// Find the old target's NEW place if we can
|
||||||
|
if (oldHandle) {
|
||||||
|
auto begin = mTargets.begin(), end = mTargets.end(),
|
||||||
|
iter = std::find(begin, end, oldHandle);
|
||||||
|
if (iter != end) {
|
||||||
|
size_t newPosition = iter - begin;
|
||||||
|
if (newPosition <= oldPosition)
|
||||||
|
mTarget = newPosition;
|
||||||
|
// else, some NEW hit and this position takes priority
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle = Target();
|
||||||
|
|
||||||
|
mLastCell = newCell;
|
||||||
|
|
||||||
|
if (!oldCell && oldHandle != handle)
|
||||||
|
// Did not move cell to cell, but did change the target
|
||||||
|
refreshCode = updateFlags;
|
||||||
|
|
||||||
|
if (handle && handle != oldHandle)
|
||||||
|
handle->Enter(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// UIHANDLE PREVIEW
|
||||||
|
// Update status message and cursor, whether dragging or not
|
||||||
|
if (handle) {
|
||||||
|
auto preview = handle->Preview( tpmState, GetProject() );
|
||||||
|
status = preview.message;
|
||||||
|
tooltip = preview.tooltip;
|
||||||
|
pCursor = preview.cursor;
|
||||||
|
auto code = handle->GetChangeHighlight();
|
||||||
|
handle->SetChangeHighlight(RefreshCode::RefreshNone);
|
||||||
|
refreshCode |= code;
|
||||||
|
mMouseOverUpdateFlags |= code;
|
||||||
|
}
|
||||||
|
if (newCell &&
|
||||||
|
(!pCursor || status.empty() || tooltip.empty())) {
|
||||||
|
// Defaulting of cursor, tooltip, and status if there is no handle,
|
||||||
|
// or if the handle does not specify them
|
||||||
|
const auto preview = newCell->DefaultPreview( tpmState, GetProject() );
|
||||||
|
if (!pCursor)
|
||||||
|
pCursor = preview.cursor;
|
||||||
|
if (status.empty())
|
||||||
|
status = preview.message;
|
||||||
|
if (tooltip.empty())
|
||||||
|
tooltip = preview.tooltip;
|
||||||
|
}
|
||||||
|
if (!pCursor) {
|
||||||
|
// Ultimate default cursor
|
||||||
|
static wxCursor defaultCursor{ wxCURSOR_DEFAULT };
|
||||||
|
pCursor = &defaultCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateStatusMessage(status);
|
||||||
|
|
||||||
|
#if wxUSE_TOOLTIPS
|
||||||
|
if (tooltip != GetToolTipText()) {
|
||||||
|
// Unset first, by analogy with AButton
|
||||||
|
UnsetToolTip();
|
||||||
|
SetToolTip(tooltip);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (pCursor)
|
||||||
|
SetCursor( *pCursor );
|
||||||
|
|
||||||
|
ProcessUIHandleResult(
|
||||||
|
newCell.get(), newCell.get(), refreshCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CellularPanel::HasRotation()
|
||||||
|
{
|
||||||
|
// Is there a nontrivial TAB key rotation?
|
||||||
|
if ( mTargets.size() > 1 )
|
||||||
|
return true;
|
||||||
|
auto target = Target();
|
||||||
|
return target && target->HasRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CellularPanel::HasEscape()
|
||||||
|
{
|
||||||
|
if (IsMouseCaptured())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (mTarget + 1 == mTargets.size() &&
|
||||||
|
Target() &&
|
||||||
|
!Target()->HasEscape())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return mTargets.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CellularPanel::ChangeTarget(bool forward, bool cycle)
|
||||||
|
{
|
||||||
|
auto size = mTargets.size();
|
||||||
|
|
||||||
|
auto target = Target();
|
||||||
|
if (target && target->HasRotation()) {
|
||||||
|
if(target->Rotate(forward))
|
||||||
|
return true;
|
||||||
|
else if (cycle && (size == 1 || IsMouseCaptured())) {
|
||||||
|
// Rotate through the states of this target only.
|
||||||
|
target->Enter(forward);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cycle &&
|
||||||
|
((forward && mTarget + 1 == size) ||
|
||||||
|
(!forward && mTarget == 0)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (size > 1) {
|
||||||
|
if (forward)
|
||||||
|
++mTarget;
|
||||||
|
else
|
||||||
|
mTarget += size - 1;
|
||||||
|
mTarget %= size;
|
||||||
|
if (Target())
|
||||||
|
Target()->Enter(forward);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines if a modal tool is active
|
||||||
|
bool CellularPanel::IsMouseCaptured()
|
||||||
|
{
|
||||||
|
return mUIHandle != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::OnContextMenu(wxContextMenuEvent & WXUNUSED(event))
|
||||||
|
{
|
||||||
|
DoContextMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Handle mouse wheel rotation (for zoom in/out, vertical and horizontal scrolling)
|
||||||
|
void CellularPanel::HandleWheelRotation( TrackPanelMouseEvent &tpmEvent )
|
||||||
|
{
|
||||||
|
auto pCell = tpmEvent.pCell;
|
||||||
|
if (!pCell)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto &event = tpmEvent.event;
|
||||||
|
double steps {};
|
||||||
|
#if defined(__WXMAC__) && defined(EVT_MAGNIFY)
|
||||||
|
// PRL:
|
||||||
|
// Pinch and spread implemented in wxWidgets 3.1.0, or cherry-picked from
|
||||||
|
// the future in custom build of 3.0.2
|
||||||
|
if (event.Magnify()) {
|
||||||
|
event.SetControlDown(true);
|
||||||
|
steps = 2 * event.GetMagnification();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
steps = event.m_wheelRotation /
|
||||||
|
(event.m_wheelDelta > 0 ? (double)event.m_wheelDelta : 120.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL) {
|
||||||
|
// Two-fingered horizontal swipe on mac is treated like shift-mousewheel
|
||||||
|
event.SetShiftDown(true);
|
||||||
|
// This makes the wave move in the same direction as the fingers, and the scrollbar
|
||||||
|
// thumb moves oppositely
|
||||||
|
steps *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tpmEvent.steps = steps;
|
||||||
|
|
||||||
|
if(!event.HasAnyModifiers()) {
|
||||||
|
// We will later un-skip if we do anything, but if we don't,
|
||||||
|
// propagate the event up for the sake of the scrubber
|
||||||
|
event.Skip();
|
||||||
|
event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned result =
|
||||||
|
pCell->HandleWheelRotation( tpmEvent, GetProject() );
|
||||||
|
ProcessUIHandleResult(
|
||||||
|
pCell.get(), pCell.get(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::OnCaptureKey(wxCommandEvent & event)
|
||||||
|
{
|
||||||
|
mEnableTab = false;
|
||||||
|
wxKeyEvent *kevent = static_cast<wxKeyEvent *>(event.GetEventObject());
|
||||||
|
const auto code = kevent->GetKeyCode();
|
||||||
|
if ( WXK_ESCAPE != code )
|
||||||
|
HandleInterruptedDrag();
|
||||||
|
|
||||||
|
// Give focused cell precedence
|
||||||
|
const auto t = GetFocusedCell();
|
||||||
|
if (t) {
|
||||||
|
const unsigned refreshResult =
|
||||||
|
t->CaptureKey(*kevent, *mViewInfo, this);
|
||||||
|
ProcessUIHandleResult(t, t, refreshResult);
|
||||||
|
event.Skip(kevent->GetSkipped());
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Special TAB key handling, but only if the cell didn't capture it
|
||||||
|
if ( !(t && !kevent->GetSkipped()) &&
|
||||||
|
WXK_TAB == code && HasRotation() ) {
|
||||||
|
// Override TAB navigation in wxWidgets, by not skipping
|
||||||
|
event.Skip(false);
|
||||||
|
mEnableTab = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
if (!t)
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::OnKeyDown(wxKeyEvent & event)
|
||||||
|
{
|
||||||
|
switch (event.GetKeyCode())
|
||||||
|
{
|
||||||
|
case WXK_ESCAPE:
|
||||||
|
if(HandleEscapeKey(true))
|
||||||
|
// Don't skip the event, eat it so that
|
||||||
|
// AudacityApp does not also stop any playback.
|
||||||
|
return;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WXK_ALT:
|
||||||
|
case WXK_SHIFT:
|
||||||
|
case WXK_CONTROL:
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
case WXK_RAW_CONTROL:
|
||||||
|
#endif
|
||||||
|
HandleModifierKey();
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
case WXK_TAB:
|
||||||
|
if ( mEnableTab && HasRotation() ) {
|
||||||
|
ChangeTarget( !event.ShiftDown(), true );
|
||||||
|
HandleCursorForPresentMouseState(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto t = GetFocusedCell();
|
||||||
|
|
||||||
|
if (t) {
|
||||||
|
const unsigned refreshResult =
|
||||||
|
t->KeyDown(event, *mViewInfo, this);
|
||||||
|
ProcessUIHandleResult(t, t, refreshResult);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::OnChar(wxKeyEvent & event)
|
||||||
|
{
|
||||||
|
switch (event.GetKeyCode())
|
||||||
|
{
|
||||||
|
case WXK_ESCAPE:
|
||||||
|
case WXK_ALT:
|
||||||
|
case WXK_SHIFT:
|
||||||
|
case WXK_CONTROL:
|
||||||
|
case WXK_PAGEUP:
|
||||||
|
case WXK_PAGEDOWN:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto t = GetFocusedCell();
|
||||||
|
if (t) {
|
||||||
|
const unsigned refreshResult =
|
||||||
|
t->Char(event, *mViewInfo, this);
|
||||||
|
ProcessUIHandleResult(t, t, refreshResult);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::OnKeyUp(wxKeyEvent & event)
|
||||||
|
{
|
||||||
|
bool didSomething = false;
|
||||||
|
switch (event.GetKeyCode())
|
||||||
|
{
|
||||||
|
case WXK_ESCAPE:
|
||||||
|
didSomething = HandleEscapeKey(false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WXK_ALT:
|
||||||
|
case WXK_SHIFT:
|
||||||
|
case WXK_CONTROL:
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
case WXK_RAW_CONTROL:
|
||||||
|
#endif
|
||||||
|
HandleModifierKey();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (didSomething)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto t = GetFocusedCell();
|
||||||
|
if (t) {
|
||||||
|
const unsigned refreshResult =
|
||||||
|
t->KeyUp(event, *mViewInfo, this);
|
||||||
|
ProcessUIHandleResult(t, t, refreshResult);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Should handle the case when the mouse capture is lost.
|
||||||
|
void CellularPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
|
||||||
|
{
|
||||||
|
ClearTargets();
|
||||||
|
|
||||||
|
// This is bad. We are lying abou the event by saying it is a mouse up.
|
||||||
|
wxMouseEvent e(wxEVT_LEFT_UP);
|
||||||
|
e.SetId( kCaptureLostEventId );
|
||||||
|
|
||||||
|
e.m_x = mMouseMostRecentX;
|
||||||
|
e.m_y = mMouseMostRecentY;
|
||||||
|
|
||||||
|
OnMouseEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This handles just generic mouse events. Then, based
|
||||||
|
/// on our current state, we forward the mouse events to
|
||||||
|
/// various interested parties.
|
||||||
|
void CellularPanel::OnMouseEvent(wxMouseEvent & event)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const auto foundCell = FindCell( event.m_x, event.m_y );
|
||||||
|
auto &rect = foundCell.rect;
|
||||||
|
auto &pCell = foundCell.pCell;
|
||||||
|
|
||||||
|
const auto size = GetSize();
|
||||||
|
TrackPanelMouseEvent tpmEvent{ event, rect, size, pCell };
|
||||||
|
|
||||||
|
#if defined(__WXMAC__) && defined(EVT_MAGNIFY)
|
||||||
|
// PRL:
|
||||||
|
// Pinch and spread implemented in wxWidgets 3.1.0, or cherry-picked from
|
||||||
|
// the future in custom build of 3.0.2
|
||||||
|
if (event.Magnify()) {
|
||||||
|
HandleWheelRotation( tpmEvent );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If a mouse event originates from a keyboard context menu event then
|
||||||
|
// event.GetPosition() == wxDefaultPosition. wxContextMenu events are handled in
|
||||||
|
// CellularPanel::OnContextMenu(), and therefore associated mouse events are ignored here.
|
||||||
|
// Not ignoring them was causing bug 613: the mouse events were interpreted as clicking
|
||||||
|
// outside the tracks.
|
||||||
|
if (event.GetPosition() == wxDefaultPosition && (event.RightDown() || event.RightUp())) {
|
||||||
|
event.Skip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.m_wheelRotation != 0)
|
||||||
|
HandleWheelRotation( tpmEvent );
|
||||||
|
|
||||||
|
if (event.LeftDown() || event.LeftIsDown() || event.Moving()) {
|
||||||
|
// Skip, even if we do something, so that the left click or drag
|
||||||
|
// may have an additional effect in the scrubber.
|
||||||
|
event.Skip();
|
||||||
|
event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
mMouseMostRecentX = event.m_x;
|
||||||
|
mMouseMostRecentY = event.m_y;
|
||||||
|
|
||||||
|
if (event.LeftDown()) {
|
||||||
|
// The activate event is used to make the
|
||||||
|
// parent window 'come alive' if it didn't have focus.
|
||||||
|
wxActivateEvent e;
|
||||||
|
GetParent()->GetEventHandler()->ProcessEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.ButtonDown()) {
|
||||||
|
SetFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.Leaving())
|
||||||
|
{
|
||||||
|
if ( !mUIHandle )
|
||||||
|
ClearTargets();
|
||||||
|
|
||||||
|
auto buttons =
|
||||||
|
// Bug 1325: button state in Leaving events is unreliable on Mac.
|
||||||
|
// Poll the global state instead.
|
||||||
|
// event.ButtonIsDown(wxMOUSE_BTN_ANY);
|
||||||
|
::wxGetMouseState().ButtonIsDown(wxMOUSE_BTN_ANY);
|
||||||
|
|
||||||
|
if(!buttons) {
|
||||||
|
CancelDragging();
|
||||||
|
|
||||||
|
#if defined(__WXMAC__)
|
||||||
|
|
||||||
|
// We must install the cursor ourselves since the window under
|
||||||
|
// the mouse is no longer this one and wx2.8.12 makes that check.
|
||||||
|
// Should re-evaluate with wx3.
|
||||||
|
wxSTANDARD_CURSOR->MacInstall();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mUIHandle) {
|
||||||
|
auto pClickedCell = mpClickedCell.lock();
|
||||||
|
if (event.Dragging()) {
|
||||||
|
// UIHANDLE DRAG
|
||||||
|
// copy shared_ptr for safety, as in HandleClick
|
||||||
|
auto handle = mUIHandle;
|
||||||
|
const UIHandle::Result refreshResult =
|
||||||
|
handle->Drag( tpmEvent, GetProject() );
|
||||||
|
ProcessUIHandleResult
|
||||||
|
(pClickedCell.get(), pCell.get(), refreshResult);
|
||||||
|
mMouseOverUpdateFlags |= refreshResult;
|
||||||
|
if (refreshResult & RefreshCode::Cancelled) {
|
||||||
|
// Drag decided to abort itself
|
||||||
|
mUIHandle.reset(), handle.reset(), ClearTargets();
|
||||||
|
mpClickedCell.reset();
|
||||||
|
Uncapture( &event );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
UpdateMouseState(event);
|
||||||
|
TrackPanelMouseState tpmState{ mLastMouseState, rect, pCell };
|
||||||
|
HandleMotion( tpmState );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (event.ButtonUp()) {
|
||||||
|
// UIHANDLE RELEASE
|
||||||
|
unsigned moreFlags = mMouseOverUpdateFlags;
|
||||||
|
UIHandle::Result refreshResult =
|
||||||
|
mUIHandle->Release( tpmEvent, GetProject(), this );
|
||||||
|
ProcessUIHandleResult
|
||||||
|
(pClickedCell.get(), pCell.get(),
|
||||||
|
refreshResult | moreFlags);
|
||||||
|
mUIHandle.reset(), ClearTargets();
|
||||||
|
mpClickedCell.reset();
|
||||||
|
// will also Uncapture() below
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( event.GetEventType() == wxEVT_MOTION )
|
||||||
|
// Update status message and cursor, not during drag
|
||||||
|
// consider it not a drag, even if button is down during motion, if
|
||||||
|
// mUIHandle is null, as it becomes during interrupted drag
|
||||||
|
// (e.g. by hitting space to play while dragging an envelope point)
|
||||||
|
HandleMotion( event );
|
||||||
|
else if ( event.ButtonDown() || event.ButtonDClick() )
|
||||||
|
HandleClick( tpmEvent );
|
||||||
|
|
||||||
|
if (event.ButtonDown() && IsMouseCaptured()) {
|
||||||
|
if (!HasCapture())
|
||||||
|
CaptureMouse();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.ButtonUp())
|
||||||
|
Uncapture();
|
||||||
|
}
|
||||||
|
catch( ... )
|
||||||
|
{
|
||||||
|
// Abort any dragging, as if by hitting Esc
|
||||||
|
if ( CancelDragging() )
|
||||||
|
;
|
||||||
|
else {
|
||||||
|
Uncapture();
|
||||||
|
Refresh(false);
|
||||||
|
}
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
|
||||||
|
{
|
||||||
|
auto pCell = tpmEvent.pCell;
|
||||||
|
|
||||||
|
// Do hit test once more, in case the button really pressed was not the
|
||||||
|
// one "anticipated."
|
||||||
|
{
|
||||||
|
TrackPanelMouseState tpmState{
|
||||||
|
tpmEvent.event,
|
||||||
|
tpmEvent.rect,
|
||||||
|
tpmEvent.pCell
|
||||||
|
};
|
||||||
|
HandleMotion( tpmState );
|
||||||
|
}
|
||||||
|
|
||||||
|
mUIHandle = Target();
|
||||||
|
|
||||||
|
if (mUIHandle) {
|
||||||
|
// UIHANDLE CLICK
|
||||||
|
// Make another shared pointer to the handle, in case recursive
|
||||||
|
// event dispatching otherwise tries to delete the handle.
|
||||||
|
auto handle = mUIHandle;
|
||||||
|
UIHandle::Result refreshResult =
|
||||||
|
handle->Click( tpmEvent, GetProject() );
|
||||||
|
if (refreshResult & RefreshCode::Cancelled)
|
||||||
|
mUIHandle.reset(), handle.reset(), ClearTargets();
|
||||||
|
else {
|
||||||
|
mpClickedCell = pCell;
|
||||||
|
|
||||||
|
// Perhaps the clicked handle wants to update cursor and state message
|
||||||
|
// after a click.
|
||||||
|
TrackPanelMouseState tpmState{
|
||||||
|
tpmEvent.event,
|
||||||
|
tpmEvent.rect,
|
||||||
|
tpmEvent.pCell
|
||||||
|
};
|
||||||
|
HandleMotion( tpmState );
|
||||||
|
}
|
||||||
|
ProcessUIHandleResult(
|
||||||
|
pCell.get(), pCell.get(), refreshResult);
|
||||||
|
mMouseOverUpdateFlags |= refreshResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::DoContextMenu( TrackPanelCell *pCell )
|
||||||
|
{
|
||||||
|
if( !pCell ) {
|
||||||
|
pCell = GetFocusedCell();
|
||||||
|
if( !pCell )
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto delegate = pCell->ContextMenuDelegate();
|
||||||
|
if (!delegate)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto rect = FindRect( *delegate );
|
||||||
|
const UIHandle::Result refreshResult =
|
||||||
|
delegate->DoContextMenu(rect, this, NULL);
|
||||||
|
|
||||||
|
// To do: use safer shared_ptr to pCell
|
||||||
|
ProcessUIHandleResult(pCell, pCell, refreshResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::OnSetFocus(wxFocusEvent & WXUNUSED(event))
|
||||||
|
{
|
||||||
|
SetFocusedCell();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CellularPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
|
||||||
|
{
|
||||||
|
if (AudacityProject::HasKeyboardCapture(this))
|
||||||
|
{
|
||||||
|
AudacityProject::ReleaseKeyboard(this);
|
||||||
|
}
|
||||||
|
Refresh( false);
|
||||||
|
}
|
148
src/CellularPanel.h
Normal file
148
src/CellularPanel.h
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
/**********************************************************************
|
||||||
|
|
||||||
|
Audacity: A Digital Audio Editor
|
||||||
|
|
||||||
|
TrackPanel.h
|
||||||
|
|
||||||
|
Paul Licameli
|
||||||
|
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
#ifndef __AUDACITY_CELLULAR_PANEL__
|
||||||
|
#define __AUDACITY_CELLULAR_PANEL__
|
||||||
|
|
||||||
|
#include <wx/cursor.h>
|
||||||
|
#include "widgets/OverlayPanel.h"
|
||||||
|
|
||||||
|
class ViewInfo;
|
||||||
|
class AudacityProject;
|
||||||
|
|
||||||
|
class TrackPanelCell;
|
||||||
|
struct TrackPanelMouseEvent;
|
||||||
|
struct TrackPanelMouseState;
|
||||||
|
|
||||||
|
class UIHandle;
|
||||||
|
using UIHandlePtr = std::shared_ptr<UIHandle>;
|
||||||
|
|
||||||
|
// This class manages a panel divided into a number of sub-rectangles called
|
||||||
|
// cells, that each implement hit tests returning click-drag-release handler
|
||||||
|
// objects, and other services.
|
||||||
|
// It has no dependency on the Track class.
|
||||||
|
class AUDACITY_DLL_API CellularPanel : public OverlayPanel {
|
||||||
|
public:
|
||||||
|
CellularPanel(wxWindow * parent, wxWindowID id,
|
||||||
|
const wxPoint & pos,
|
||||||
|
const wxSize & size,
|
||||||
|
ViewInfo *viewInfo,
|
||||||
|
// default as for wxPanel:
|
||||||
|
long style = wxTAB_TRAVERSAL | wxNO_BORDER)
|
||||||
|
: OverlayPanel(parent, id, pos, size, style)
|
||||||
|
, mViewInfo( viewInfo )
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Overridables:
|
||||||
|
|
||||||
|
virtual AudacityProject *GetProject() const = 0;
|
||||||
|
|
||||||
|
// Find track info by coordinate
|
||||||
|
struct FoundCell {
|
||||||
|
std::shared_ptr<TrackPanelCell> pCell;
|
||||||
|
wxRect rect;
|
||||||
|
};
|
||||||
|
virtual FoundCell FindCell(int mouseX, int mouseY) = 0;
|
||||||
|
virtual wxRect FindRect(const TrackPanelCell &cell) = 0;
|
||||||
|
virtual TrackPanelCell *GetFocusedCell() = 0;
|
||||||
|
virtual void SetFocusedCell() = 0;
|
||||||
|
|
||||||
|
virtual void ProcessUIHandleResult
|
||||||
|
(TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell,
|
||||||
|
unsigned refreshResult) = 0;
|
||||||
|
|
||||||
|
virtual void UpdateStatusMessage( const wxString & ) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UIHandlePtr Target()
|
||||||
|
{
|
||||||
|
if (mTargets.size())
|
||||||
|
return mTargets[mTarget];
|
||||||
|
else
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsMouseCaptured();
|
||||||
|
|
||||||
|
wxCoord MostRecentXCoord() const { return mMouseMostRecentX; }
|
||||||
|
|
||||||
|
void HandleCursorForPresentMouseState(bool doHit = true);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool HasEscape();
|
||||||
|
bool CancelDragging();
|
||||||
|
void DoContextMenu( TrackPanelCell *pCell = nullptr );
|
||||||
|
void ClearTargets()
|
||||||
|
{
|
||||||
|
// Forget the rotation of hit test candidates when the mouse moves from
|
||||||
|
// cell to cell or outside of the panel entirely.
|
||||||
|
mLastCell.reset();
|
||||||
|
mTargets.clear();
|
||||||
|
mTarget = 0;
|
||||||
|
mMouseOverUpdateFlags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool HasRotation();
|
||||||
|
bool ChangeTarget(bool forward, bool cycle);
|
||||||
|
|
||||||
|
void OnMouseEvent(wxMouseEvent & event);
|
||||||
|
void OnCaptureLost(wxMouseCaptureLostEvent & event);
|
||||||
|
void OnCaptureKey(wxCommandEvent & event);
|
||||||
|
void OnKeyDown(wxKeyEvent & event);
|
||||||
|
void OnChar(wxKeyEvent & event);
|
||||||
|
void OnKeyUp(wxKeyEvent & event);
|
||||||
|
|
||||||
|
void OnSetFocus(wxFocusEvent & event);
|
||||||
|
void OnKillFocus(wxFocusEvent & event);
|
||||||
|
|
||||||
|
void OnContextMenu(wxContextMenuEvent & event);
|
||||||
|
|
||||||
|
void HandleInterruptedDrag();
|
||||||
|
void Uncapture( wxMouseState *pState = nullptr );
|
||||||
|
bool HandleEscapeKey(bool down);
|
||||||
|
void UpdateMouseState(const wxMouseState &state);
|
||||||
|
void HandleModifierKey();
|
||||||
|
|
||||||
|
void HandleClick( const TrackPanelMouseEvent &tpmEvent );
|
||||||
|
void HandleWheelRotation( TrackPanelMouseEvent &tpmEvent );
|
||||||
|
|
||||||
|
void HandleMotion( wxMouseState &state, bool doHit = true );
|
||||||
|
void HandleMotion
|
||||||
|
( const TrackPanelMouseState &tpmState, bool doHit = true );
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ViewInfo *mViewInfo;
|
||||||
|
|
||||||
|
private:
|
||||||
|
UIHandlePtr mUIHandle;
|
||||||
|
|
||||||
|
std::weak_ptr<TrackPanelCell> mLastCell;
|
||||||
|
std::vector<UIHandlePtr> mTargets;
|
||||||
|
size_t mTarget {};
|
||||||
|
unsigned mMouseOverUpdateFlags{};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// To do: make a drawing method and make this private
|
||||||
|
wxMouseState mLastMouseState;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mMouseMostRecentX;
|
||||||
|
int mMouseMostRecentY;
|
||||||
|
|
||||||
|
std::weak_ptr<TrackPanelCell> mpClickedCell;
|
||||||
|
|
||||||
|
bool mEnableTab{};
|
||||||
|
|
||||||
|
DECLARE_EVENT_TABLE()
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -121,6 +121,8 @@ audacity_SOURCES = \
|
|||||||
BatchProcessDialog.h \
|
BatchProcessDialog.h \
|
||||||
Benchmark.cpp \
|
Benchmark.cpp \
|
||||||
Benchmark.h \
|
Benchmark.h \
|
||||||
|
CellularPanel.cpp \
|
||||||
|
CellularPanel.h \
|
||||||
Dependencies.cpp \
|
Dependencies.cpp \
|
||||||
Dependencies.h \
|
Dependencies.h \
|
||||||
DeviceChange.cpp \
|
DeviceChange.cpp \
|
||||||
|
113
src/Makefile.in
113
src/Makefile.in
@ -1,7 +1,7 @@
|
|||||||
# Makefile.in generated by automake 1.14.1 from Makefile.am.
|
# Makefile.in generated by automake 1.15 from Makefile.am.
|
||||||
# @configure_input@
|
# @configure_input@
|
||||||
|
|
||||||
# Copyright (C) 1994-2013 Free Software Foundation, Inc.
|
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
|
||||||
|
|
||||||
# This Makefile.in is free software; the Free Software Foundation
|
# This Makefile.in is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
@ -16,7 +16,17 @@
|
|||||||
|
|
||||||
|
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
|
am__is_gnu_make = { \
|
||||||
|
if test -z '$(MAKELEVEL)'; then \
|
||||||
|
false; \
|
||||||
|
elif test -n '$(MAKE_HOST)'; then \
|
||||||
|
true; \
|
||||||
|
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||||
|
true; \
|
||||||
|
else \
|
||||||
|
false; \
|
||||||
|
fi; \
|
||||||
|
}
|
||||||
am__make_running_with_option = \
|
am__make_running_with_option = \
|
||||||
case $${target_option-} in \
|
case $${target_option-} in \
|
||||||
?) ;; \
|
?) ;; \
|
||||||
@ -190,9 +200,6 @@ bin_PROGRAMS = audacity$(EXEEXT)
|
|||||||
@USE_VST_TRUE@ $(NULL)
|
@USE_VST_TRUE@ $(NULL)
|
||||||
|
|
||||||
subdir = src
|
subdir = src
|
||||||
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
|
|
||||||
$(srcdir)/configtemplate.h $(srcdir)/audacity.desktop.in \
|
|
||||||
$(top_srcdir)/autotools/depcomp $(dist_mime_DATA)
|
|
||||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_c99_func_lrint.m4 \
|
am__aclocal_m4_deps = $(top_srcdir)/m4/ac_c99_func_lrint.m4 \
|
||||||
$(top_srcdir)/m4/ac_c99_func_lrintf.m4 \
|
$(top_srcdir)/m4/ac_c99_func_lrintf.m4 \
|
||||||
@ -235,6 +242,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ac_c99_func_lrint.m4 \
|
|||||||
$(top_srcdir)/configure.ac
|
$(top_srcdir)/configure.ac
|
||||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||||
$(ACLOCAL_M4)
|
$(ACLOCAL_M4)
|
||||||
|
DIST_COMMON = $(srcdir)/Makefile.am $(dist_mime_DATA) \
|
||||||
|
$(am__DIST_COMMON)
|
||||||
mkinstalldirs = $(install_sh) -d
|
mkinstalldirs = $(install_sh) -d
|
||||||
CONFIG_HEADER = configwin.h configunix.h
|
CONFIG_HEADER = configwin.h configunix.h
|
||||||
CONFIG_CLEAN_FILES = audacity.desktop
|
CONFIG_CLEAN_FILES = audacity.desktop
|
||||||
@ -287,22 +296,23 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \
|
|||||||
AutoRecovery.h BatchCommandDialog.cpp BatchCommandDialog.h \
|
AutoRecovery.h BatchCommandDialog.cpp BatchCommandDialog.h \
|
||||||
BatchCommands.cpp BatchCommands.h BatchProcessDialog.cpp \
|
BatchCommands.cpp BatchCommands.h BatchProcessDialog.cpp \
|
||||||
BatchProcessDialog.h Benchmark.cpp Benchmark.h \
|
BatchProcessDialog.h Benchmark.cpp Benchmark.h \
|
||||||
Dependencies.cpp Dependencies.h DeviceChange.cpp \
|
CellularPanel.cpp CellularPanel.h Dependencies.cpp \
|
||||||
DeviceChange.h DeviceManager.cpp DeviceManager.h Diags.cpp \
|
Dependencies.h DeviceChange.cpp DeviceChange.h \
|
||||||
Diags.h Envelope.cpp Envelope.h Experimental.h FFmpeg.cpp \
|
DeviceManager.cpp DeviceManager.h Diags.cpp Diags.h \
|
||||||
FFmpeg.h FFT.cpp FFT.h FileException.cpp FileException.h \
|
Envelope.cpp Envelope.h Experimental.h FFmpeg.cpp FFmpeg.h \
|
||||||
FileIO.cpp FileIO.h FileNames.cpp FileNames.h float_cast.h \
|
FFT.cpp FFT.h FileException.cpp FileException.h FileIO.cpp \
|
||||||
FreqWindow.cpp FreqWindow.h HelpText.cpp HelpText.h \
|
FileIO.h FileNames.cpp FileNames.h float_cast.h FreqWindow.cpp \
|
||||||
HistoryWindow.cpp HistoryWindow.h HitTestResult.h \
|
FreqWindow.h HelpText.cpp HelpText.h HistoryWindow.cpp \
|
||||||
ImageManipulation.cpp ImageManipulation.h \
|
HistoryWindow.h HitTestResult.h ImageManipulation.cpp \
|
||||||
InconsistencyException.cpp InconsistencyException.h \
|
ImageManipulation.h InconsistencyException.cpp \
|
||||||
InterpolateAudio.cpp InterpolateAudio.h LabelDialog.cpp \
|
InconsistencyException.h InterpolateAudio.cpp \
|
||||||
LabelDialog.h LabelTrack.cpp LabelTrack.h LangChoice.cpp \
|
InterpolateAudio.h LabelDialog.cpp LabelDialog.h \
|
||||||
LangChoice.h Languages.cpp Languages.h Legacy.cpp Legacy.h \
|
LabelTrack.cpp LabelTrack.h LangChoice.cpp LangChoice.h \
|
||||||
Lyrics.cpp Lyrics.h LyricsWindow.cpp LyricsWindow.h \
|
Languages.cpp Languages.h Legacy.cpp Legacy.h Lyrics.cpp \
|
||||||
MacroMagic.h Matrix.cpp Matrix.h MemoryX.h Menus.cpp Menus.h \
|
Lyrics.h LyricsWindow.cpp LyricsWindow.h MacroMagic.h \
|
||||||
Mix.cpp Mix.h MixerBoard.cpp MixerBoard.h ModuleManager.cpp \
|
Matrix.cpp Matrix.h MemoryX.h Menus.cpp Menus.h Mix.cpp Mix.h \
|
||||||
ModuleManager.h NumberScale.h PitchName.cpp PitchName.h \
|
MixerBoard.cpp MixerBoard.h ModuleManager.cpp ModuleManager.h \
|
||||||
|
NumberScale.h PitchName.cpp PitchName.h \
|
||||||
PlatformCompatibility.cpp PlatformCompatibility.h \
|
PlatformCompatibility.cpp PlatformCompatibility.h \
|
||||||
PluginManager.cpp PluginManager.h Printing.cpp Printing.h \
|
PluginManager.cpp PluginManager.h Printing.cpp Printing.h \
|
||||||
Profiler.cpp Profiler.h Project.cpp Project.h RealFFTf.cpp \
|
Profiler.cpp Profiler.h Project.cpp Project.h RealFFTf.cpp \
|
||||||
@ -612,7 +622,8 @@ am_audacity_OBJECTS = $(am__objects_1) audacity-AboutDialog.$(OBJEXT) \
|
|||||||
audacity-BatchCommandDialog.$(OBJEXT) \
|
audacity-BatchCommandDialog.$(OBJEXT) \
|
||||||
audacity-BatchCommands.$(OBJEXT) \
|
audacity-BatchCommands.$(OBJEXT) \
|
||||||
audacity-BatchProcessDialog.$(OBJEXT) \
|
audacity-BatchProcessDialog.$(OBJEXT) \
|
||||||
audacity-Benchmark.$(OBJEXT) audacity-Dependencies.$(OBJEXT) \
|
audacity-Benchmark.$(OBJEXT) audacity-CellularPanel.$(OBJEXT) \
|
||||||
|
audacity-Dependencies.$(OBJEXT) \
|
||||||
audacity-DeviceChange.$(OBJEXT) \
|
audacity-DeviceChange.$(OBJEXT) \
|
||||||
audacity-DeviceManager.$(OBJEXT) audacity-Diags.$(OBJEXT) \
|
audacity-DeviceManager.$(OBJEXT) audacity-Diags.$(OBJEXT) \
|
||||||
audacity-Envelope.$(OBJEXT) audacity-FFmpeg.$(OBJEXT) \
|
audacity-Envelope.$(OBJEXT) audacity-FFmpeg.$(OBJEXT) \
|
||||||
@ -1008,6 +1019,8 @@ am__define_uniq_tagged_files = \
|
|||||||
done | $(am__uniquify_input)`
|
done | $(am__uniquify_input)`
|
||||||
ETAGS = etags
|
ETAGS = etags
|
||||||
CTAGS = ctags
|
CTAGS = ctags
|
||||||
|
am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/audacity.desktop.in \
|
||||||
|
$(srcdir)/configtemplate.h $(top_srcdir)/autotools/depcomp
|
||||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||||
ACLOCAL = @ACLOCAL@
|
ACLOCAL = @ACLOCAL@
|
||||||
AMTAR = @AMTAR@
|
AMTAR = @AMTAR@
|
||||||
@ -1102,6 +1115,7 @@ LN_S = @LN_S@
|
|||||||
LTLIBICONV = @LTLIBICONV@
|
LTLIBICONV = @LTLIBICONV@
|
||||||
LTLIBINTL = @LTLIBINTL@
|
LTLIBINTL = @LTLIBINTL@
|
||||||
LTLIBOBJS = @LTLIBOBJS@
|
LTLIBOBJS = @LTLIBOBJS@
|
||||||
|
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||||
LV2_CFLAGS = @LV2_CFLAGS@
|
LV2_CFLAGS = @LV2_CFLAGS@
|
||||||
LV2_LIBS = @LV2_LIBS@
|
LV2_LIBS = @LV2_LIBS@
|
||||||
MAINT = @MAINT@
|
MAINT = @MAINT@
|
||||||
@ -1127,6 +1141,8 @@ PACKAGE_URL = @PACKAGE_URL@
|
|||||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||||
PKG_CONFIG = @PKG_CONFIG@
|
PKG_CONFIG = @PKG_CONFIG@
|
||||||
|
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||||
|
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||||
PORTAUDIO_CFLAGS = @PORTAUDIO_CFLAGS@
|
PORTAUDIO_CFLAGS = @PORTAUDIO_CFLAGS@
|
||||||
PORTAUDIO_LIBS = @PORTAUDIO_LIBS@
|
PORTAUDIO_LIBS = @PORTAUDIO_LIBS@
|
||||||
PORTMIDI_CFLAGS = @PORTMIDI_CFLAGS@
|
PORTMIDI_CFLAGS = @PORTMIDI_CFLAGS@
|
||||||
@ -1308,22 +1324,23 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \
|
|||||||
AutoRecovery.h BatchCommandDialog.cpp BatchCommandDialog.h \
|
AutoRecovery.h BatchCommandDialog.cpp BatchCommandDialog.h \
|
||||||
BatchCommands.cpp BatchCommands.h BatchProcessDialog.cpp \
|
BatchCommands.cpp BatchCommands.h BatchProcessDialog.cpp \
|
||||||
BatchProcessDialog.h Benchmark.cpp Benchmark.h \
|
BatchProcessDialog.h Benchmark.cpp Benchmark.h \
|
||||||
Dependencies.cpp Dependencies.h DeviceChange.cpp \
|
CellularPanel.cpp CellularPanel.h Dependencies.cpp \
|
||||||
DeviceChange.h DeviceManager.cpp DeviceManager.h Diags.cpp \
|
Dependencies.h DeviceChange.cpp DeviceChange.h \
|
||||||
Diags.h Envelope.cpp Envelope.h Experimental.h FFmpeg.cpp \
|
DeviceManager.cpp DeviceManager.h Diags.cpp Diags.h \
|
||||||
FFmpeg.h FFT.cpp FFT.h FileException.cpp FileException.h \
|
Envelope.cpp Envelope.h Experimental.h FFmpeg.cpp FFmpeg.h \
|
||||||
FileIO.cpp FileIO.h FileNames.cpp FileNames.h float_cast.h \
|
FFT.cpp FFT.h FileException.cpp FileException.h FileIO.cpp \
|
||||||
FreqWindow.cpp FreqWindow.h HelpText.cpp HelpText.h \
|
FileIO.h FileNames.cpp FileNames.h float_cast.h FreqWindow.cpp \
|
||||||
HistoryWindow.cpp HistoryWindow.h HitTestResult.h \
|
FreqWindow.h HelpText.cpp HelpText.h HistoryWindow.cpp \
|
||||||
ImageManipulation.cpp ImageManipulation.h \
|
HistoryWindow.h HitTestResult.h ImageManipulation.cpp \
|
||||||
InconsistencyException.cpp InconsistencyException.h \
|
ImageManipulation.h InconsistencyException.cpp \
|
||||||
InterpolateAudio.cpp InterpolateAudio.h LabelDialog.cpp \
|
InconsistencyException.h InterpolateAudio.cpp \
|
||||||
LabelDialog.h LabelTrack.cpp LabelTrack.h LangChoice.cpp \
|
InterpolateAudio.h LabelDialog.cpp LabelDialog.h \
|
||||||
LangChoice.h Languages.cpp Languages.h Legacy.cpp Legacy.h \
|
LabelTrack.cpp LabelTrack.h LangChoice.cpp LangChoice.h \
|
||||||
Lyrics.cpp Lyrics.h LyricsWindow.cpp LyricsWindow.h \
|
Languages.cpp Languages.h Legacy.cpp Legacy.h Lyrics.cpp \
|
||||||
MacroMagic.h Matrix.cpp Matrix.h MemoryX.h Menus.cpp Menus.h \
|
Lyrics.h LyricsWindow.cpp LyricsWindow.h MacroMagic.h \
|
||||||
Mix.cpp Mix.h MixerBoard.cpp MixerBoard.h ModuleManager.cpp \
|
Matrix.cpp Matrix.h MemoryX.h Menus.cpp Menus.h Mix.cpp Mix.h \
|
||||||
ModuleManager.h NumberScale.h PitchName.cpp PitchName.h \
|
MixerBoard.cpp MixerBoard.h ModuleManager.cpp ModuleManager.h \
|
||||||
|
NumberScale.h PitchName.cpp PitchName.h \
|
||||||
PlatformCompatibility.cpp PlatformCompatibility.h \
|
PlatformCompatibility.cpp PlatformCompatibility.h \
|
||||||
PluginManager.cpp PluginManager.h Printing.cpp Printing.h \
|
PluginManager.cpp PluginManager.h Printing.cpp Printing.h \
|
||||||
Profiler.cpp Profiler.h Project.cpp Project.h RealFFTf.cpp \
|
Profiler.cpp Profiler.h Project.cpp Project.h RealFFTf.cpp \
|
||||||
@ -1602,7 +1619,6 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi
|
|||||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
|
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
|
||||||
$(am__cd) $(top_srcdir) && \
|
$(am__cd) $(top_srcdir) && \
|
||||||
$(AUTOMAKE) --foreign src/Makefile
|
$(AUTOMAKE) --foreign src/Makefile
|
||||||
.PRECIOUS: Makefile
|
|
||||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||||
@case '$?' in \
|
@case '$?' in \
|
||||||
*config.status*) \
|
*config.status*) \
|
||||||
@ -2408,6 +2424,7 @@ distclean-compile:
|
|||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-BatchProcessDialog.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-BatchProcessDialog.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Benchmark.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Benchmark.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-BlockFile.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-BlockFile.Po@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-CellularPanel.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Dependencies.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-Dependencies.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-DeviceChange.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-DeviceChange.Po@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-DeviceManager.Po@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audacity-DeviceManager.Po@am__quote@
|
||||||
@ -3273,6 +3290,20 @@ audacity-Benchmark.obj: Benchmark.cpp
|
|||||||
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-Benchmark.obj `if test -f 'Benchmark.cpp'; then $(CYGPATH_W) 'Benchmark.cpp'; else $(CYGPATH_W) '$(srcdir)/Benchmark.cpp'; fi`
|
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-Benchmark.obj `if test -f 'Benchmark.cpp'; then $(CYGPATH_W) 'Benchmark.cpp'; else $(CYGPATH_W) '$(srcdir)/Benchmark.cpp'; fi`
|
||||||
|
|
||||||
|
audacity-CellularPanel.o: CellularPanel.cpp
|
||||||
|
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-CellularPanel.o -MD -MP -MF $(DEPDIR)/audacity-CellularPanel.Tpo -c -o audacity-CellularPanel.o `test -f 'CellularPanel.cpp' || echo '$(srcdir)/'`CellularPanel.cpp
|
||||||
|
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-CellularPanel.Tpo $(DEPDIR)/audacity-CellularPanel.Po
|
||||||
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CellularPanel.cpp' object='audacity-CellularPanel.o' libtool=no @AMDEPBACKSLASH@
|
||||||
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
|
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-CellularPanel.o `test -f 'CellularPanel.cpp' || echo '$(srcdir)/'`CellularPanel.cpp
|
||||||
|
|
||||||
|
audacity-CellularPanel.obj: CellularPanel.cpp
|
||||||
|
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-CellularPanel.obj -MD -MP -MF $(DEPDIR)/audacity-CellularPanel.Tpo -c -o audacity-CellularPanel.obj `if test -f 'CellularPanel.cpp'; then $(CYGPATH_W) 'CellularPanel.cpp'; else $(CYGPATH_W) '$(srcdir)/CellularPanel.cpp'; fi`
|
||||||
|
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-CellularPanel.Tpo $(DEPDIR)/audacity-CellularPanel.Po
|
||||||
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CellularPanel.cpp' object='audacity-CellularPanel.obj' libtool=no @AMDEPBACKSLASH@
|
||||||
|
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
|
@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o audacity-CellularPanel.obj `if test -f 'CellularPanel.cpp'; then $(CYGPATH_W) 'CellularPanel.cpp'; else $(CYGPATH_W) '$(srcdir)/CellularPanel.cpp'; fi`
|
||||||
|
|
||||||
audacity-Dependencies.o: Dependencies.cpp
|
audacity-Dependencies.o: Dependencies.cpp
|
||||||
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-Dependencies.o -MD -MP -MF $(DEPDIR)/audacity-Dependencies.Tpo -c -o audacity-Dependencies.o `test -f 'Dependencies.cpp' || echo '$(srcdir)/'`Dependencies.cpp
|
@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT audacity-Dependencies.o -MD -MP -MF $(DEPDIR)/audacity-Dependencies.Tpo -c -o audacity-Dependencies.o `test -f 'Dependencies.cpp' || echo '$(srcdir)/'`Dependencies.cpp
|
||||||
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-Dependencies.Tpo $(DEPDIR)/audacity-Dependencies.Po
|
@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/audacity-Dependencies.Tpo $(DEPDIR)/audacity-Dependencies.Po
|
||||||
@ -7722,6 +7753,8 @@ uninstall-am: uninstall-binPROGRAMS uninstall-desktopDATA \
|
|||||||
tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \
|
tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \
|
||||||
uninstall-desktopDATA uninstall-dist_mimeDATA
|
uninstall-desktopDATA uninstall-dist_mimeDATA
|
||||||
|
|
||||||
|
.PRECIOUS: Makefile
|
||||||
|
|
||||||
|
|
||||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||||
|
@ -169,8 +169,6 @@ is time to refresh some aspect of the screen.
|
|||||||
#include "RefreshCode.h"
|
#include "RefreshCode.h"
|
||||||
#include "TrackArtist.h"
|
#include "TrackArtist.h"
|
||||||
#include "TrackPanelAx.h"
|
#include "TrackPanelAx.h"
|
||||||
#include "UIHandle.h"
|
|
||||||
#include "HitTestResult.h"
|
|
||||||
#include "WaveTrack.h"
|
#include "WaveTrack.h"
|
||||||
#ifdef EXPERIMENTAL_MIDI_OUT
|
#ifdef EXPERIMENTAL_MIDI_OUT
|
||||||
#include "NoteTrack.h"
|
#include "NoteTrack.h"
|
||||||
@ -254,18 +252,6 @@ template < class A, class B, class DIST > bool within(A a, B b, DIST d)
|
|||||||
return (a > b - d) && (a < b + d);
|
return (a > b - d) && (a < b + d);
|
||||||
}
|
}
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(CellularPanel, OverlayPanel)
|
|
||||||
EVT_MOUSE_EVENTS(CellularPanel::OnMouseEvent)
|
|
||||||
EVT_MOUSE_CAPTURE_LOST(CellularPanel::OnCaptureLost)
|
|
||||||
EVT_COMMAND(wxID_ANY, EVT_CAPTURE_KEY, CellularPanel::OnCaptureKey)
|
|
||||||
EVT_KEY_DOWN(CellularPanel::OnKeyDown)
|
|
||||||
EVT_KEY_UP(CellularPanel::OnKeyUp)
|
|
||||||
EVT_CHAR(CellularPanel::OnChar)
|
|
||||||
EVT_SET_FOCUS(CellularPanel::OnSetFocus)
|
|
||||||
EVT_KILL_FOCUS(CellularPanel::OnKillFocus)
|
|
||||||
EVT_CONTEXT_MENU(CellularPanel::OnContextMenu)
|
|
||||||
END_EVENT_TABLE()
|
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(TrackPanel, CellularPanel)
|
BEGIN_EVENT_TABLE(TrackPanel, CellularPanel)
|
||||||
EVT_MOUSE_EVENTS(TrackPanel::OnMouseEvent)
|
EVT_MOUSE_EVENTS(TrackPanel::OnMouseEvent)
|
||||||
EVT_KEY_DOWN(TrackPanel::OnKeyDown)
|
EVT_KEY_DOWN(TrackPanel::OnKeyDown)
|
||||||
@ -620,20 +606,6 @@ void TrackPanel::MakeParentRedrawScrollbars()
|
|||||||
mListener->TP_RedrawScrollbars();
|
mListener->TP_RedrawScrollbars();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellularPanel::HandleInterruptedDrag()
|
|
||||||
{
|
|
||||||
if (mUIHandle && mUIHandle->StopsOnKeystroke() ) {
|
|
||||||
// The bogus id isn't used anywhere, but may help with debugging.
|
|
||||||
// as this is sending a bogus mouse up. The mouse button is still actually down
|
|
||||||
// and may go up again.
|
|
||||||
const int idBogusUp = 2;
|
|
||||||
wxMouseEvent evt { wxEVT_LEFT_UP };
|
|
||||||
evt.SetId( idBogusUp );
|
|
||||||
evt.SetPosition(this->ScreenToClient(::wxGetMousePosition()));
|
|
||||||
this->ProcessEvent(evt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::shared_ptr<Track> FindTrack(TrackPanelCell *pCell )
|
std::shared_ptr<Track> FindTrack(TrackPanelCell *pCell )
|
||||||
{
|
{
|
||||||
@ -724,91 +696,6 @@ void TrackPanel::ProcessUIHandleResult
|
|||||||
panel->EnsureVisible(pClickedTrack);
|
panel->EnsureVisible(pClickedTrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellularPanel::Uncapture(wxMouseState *pState)
|
|
||||||
{
|
|
||||||
auto state = ::wxGetMouseState();
|
|
||||||
if (!pState) {
|
|
||||||
// Remap the position
|
|
||||||
state.SetPosition(this->ScreenToClient(state.GetPosition()));
|
|
||||||
pState = &state;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HasCapture())
|
|
||||||
ReleaseMouse();
|
|
||||||
HandleMotion( *pState );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CellularPanel::CancelDragging()
|
|
||||||
{
|
|
||||||
if (mUIHandle) {
|
|
||||||
// copy shared_ptr for safety, as in HandleClick
|
|
||||||
auto handle = mUIHandle;
|
|
||||||
// UIHANDLE CANCEL
|
|
||||||
UIHandle::Result refreshResult = handle->Cancel(GetProject());
|
|
||||||
auto pClickedCell = mpClickedCell.lock();
|
|
||||||
if (pClickedCell)
|
|
||||||
ProcessUIHandleResult(
|
|
||||||
pClickedCell.get(), {},
|
|
||||||
refreshResult | mMouseOverUpdateFlags );
|
|
||||||
mpClickedCell.reset();
|
|
||||||
mUIHandle.reset(), handle.reset(), ClearTargets();
|
|
||||||
Uncapture();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CellularPanel::HandleEscapeKey(bool down)
|
|
||||||
{
|
|
||||||
if (!down)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
{
|
|
||||||
auto target = Target();
|
|
||||||
if (target && target->HasEscape() && target->Escape()) {
|
|
||||||
HandleCursorForPresentMouseState(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mUIHandle) {
|
|
||||||
CancelDragging();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ChangeTarget(true, false)) {
|
|
||||||
HandleCursorForPresentMouseState(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CellularPanel::UpdateMouseState(const wxMouseState &state)
|
|
||||||
{
|
|
||||||
mLastMouseState = state;
|
|
||||||
|
|
||||||
// Simulate a down button if none, so hit test routines can anticipate
|
|
||||||
// which button will be clicked
|
|
||||||
if (!state.ButtonIsDown(wxMOUSE_BTN_ANY)) {
|
|
||||||
#ifdef __WXOSX__
|
|
||||||
if (state.RawControlDown())
|
|
||||||
// On Mac we can distinctly anticipate "right" click (as Control+click)
|
|
||||||
mLastMouseState.SetRightDown( true ),
|
|
||||||
mLastMouseState.SetLeftDown( false );
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
// Anticipate a left click by default
|
|
||||||
mLastMouseState.SetRightDown( false ),
|
|
||||||
mLastMouseState.SetLeftDown( true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CellularPanel::HandleModifierKey()
|
|
||||||
{
|
|
||||||
HandleCursorForPresentMouseState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackPanel::HandlePageUpKey()
|
void TrackPanel::HandlePageUpKey()
|
||||||
{
|
{
|
||||||
mListener->TP_ScrollWindow(2 * mViewInfo->h - GetScreenEndTime());
|
mListener->TP_ScrollWindow(2 * mViewInfo->h - GetScreenEndTime());
|
||||||
@ -819,165 +706,12 @@ void TrackPanel::HandlePageDownKey()
|
|||||||
mListener->TP_ScrollWindow(GetScreenEndTime());
|
mListener->TP_ScrollWindow(GetScreenEndTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellularPanel::HandleCursorForPresentMouseState(bool doHit)
|
|
||||||
{
|
|
||||||
// Come here on modifier key or mouse button transitions,
|
|
||||||
// or on starting or stopping of play or record,
|
|
||||||
// or change of toolbar button,
|
|
||||||
// and change the cursor appropriately.
|
|
||||||
|
|
||||||
// Get the button and key states
|
|
||||||
auto state = ::wxGetMouseState();
|
|
||||||
// Remap the position
|
|
||||||
state.SetPosition(this->ScreenToClient(state.GetPosition()));
|
|
||||||
|
|
||||||
HandleMotion( state, doHit );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TrackPanel::IsAudioActive()
|
bool TrackPanel::IsAudioActive()
|
||||||
{
|
{
|
||||||
AudacityProject *p = GetProject();
|
AudacityProject *p = GetProject();
|
||||||
return p->IsAudioActive();
|
return p->IsAudioActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// TrackPanel::HandleMotion( ) sets the cursor drawn at the mouse location,
|
|
||||||
/// and updates the status bar message.
|
|
||||||
/// We treat certain other changes of mouse button and key state as "motions"
|
|
||||||
/// too, and also starting and stopping of playback or recording, all of which
|
|
||||||
/// may cause the appropriate cursor and message to change.
|
|
||||||
/// As this procedure checks which region the mouse is over, it is
|
|
||||||
/// appropriate to establish the message in the status bar.
|
|
||||||
void CellularPanel::HandleMotion( wxMouseState &inState, bool doHit )
|
|
||||||
{
|
|
||||||
UpdateMouseState( inState );
|
|
||||||
|
|
||||||
const auto foundCell = FindCell( inState.m_x, inState.m_y );
|
|
||||||
auto &rect = foundCell.rect;
|
|
||||||
auto &pCell = foundCell.pCell;
|
|
||||||
const TrackPanelMouseState tpmState{ mLastMouseState, rect, pCell };
|
|
||||||
HandleMotion( tpmState, doHit );
|
|
||||||
}
|
|
||||||
|
|
||||||
void CellularPanel::HandleMotion
|
|
||||||
( const TrackPanelMouseState &tpmState, bool doHit )
|
|
||||||
{
|
|
||||||
auto handle = mUIHandle;
|
|
||||||
|
|
||||||
auto newCell = tpmState.pCell;
|
|
||||||
|
|
||||||
wxString status{}, tooltip{};
|
|
||||||
wxCursor *pCursor{};
|
|
||||||
unsigned refreshCode = 0;
|
|
||||||
|
|
||||||
if ( ! doHit ) {
|
|
||||||
// Dragging or not
|
|
||||||
handle = Target();
|
|
||||||
|
|
||||||
// Assume cell does not change but target does
|
|
||||||
refreshCode = mMouseOverUpdateFlags;
|
|
||||||
mMouseOverUpdateFlags = 0;
|
|
||||||
}
|
|
||||||
else if ( !mUIHandle ) {
|
|
||||||
// Not yet dragging.
|
|
||||||
|
|
||||||
auto oldCell = mLastCell.lock();
|
|
||||||
|
|
||||||
unsigned updateFlags = mMouseOverUpdateFlags;
|
|
||||||
|
|
||||||
// First check whether crossing cell to cell
|
|
||||||
if ( newCell == oldCell )
|
|
||||||
oldCell.reset();
|
|
||||||
else {
|
|
||||||
// Forget old targets
|
|
||||||
ClearTargets();
|
|
||||||
// Re-draw any highlighting
|
|
||||||
if (oldCell) {
|
|
||||||
ProcessUIHandleResult(
|
|
||||||
oldCell.get(), oldCell.get(), updateFlags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto oldHandle = Target();
|
|
||||||
auto oldPosition = mTarget;
|
|
||||||
|
|
||||||
// Now do the
|
|
||||||
// UIHANDLE HIT TEST !
|
|
||||||
mTargets = newCell->HitTest(tpmState, GetProject());
|
|
||||||
|
|
||||||
mTarget = 0;
|
|
||||||
|
|
||||||
// Find the old target's NEW place if we can
|
|
||||||
if (oldHandle) {
|
|
||||||
auto begin = mTargets.begin(), end = mTargets.end(),
|
|
||||||
iter = std::find(begin, end, oldHandle);
|
|
||||||
if (iter != end) {
|
|
||||||
size_t newPosition = iter - begin;
|
|
||||||
if (newPosition <= oldPosition)
|
|
||||||
mTarget = newPosition;
|
|
||||||
// else, some NEW hit and this position takes priority
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handle = Target();
|
|
||||||
|
|
||||||
mLastCell = newCell;
|
|
||||||
|
|
||||||
if (!oldCell && oldHandle != handle)
|
|
||||||
// Did not move cell to cell, but did change the target
|
|
||||||
refreshCode = updateFlags;
|
|
||||||
|
|
||||||
if (handle && handle != oldHandle)
|
|
||||||
handle->Enter(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// UIHANDLE PREVIEW
|
|
||||||
// Update status message and cursor, whether dragging or not
|
|
||||||
if (handle) {
|
|
||||||
auto preview = handle->Preview( tpmState, GetProject() );
|
|
||||||
status = preview.message;
|
|
||||||
tooltip = preview.tooltip;
|
|
||||||
pCursor = preview.cursor;
|
|
||||||
auto code = handle->GetChangeHighlight();
|
|
||||||
handle->SetChangeHighlight(RefreshCode::RefreshNone);
|
|
||||||
refreshCode |= code;
|
|
||||||
mMouseOverUpdateFlags |= code;
|
|
||||||
}
|
|
||||||
if (newCell &&
|
|
||||||
(!pCursor || status.empty() || tooltip.empty())) {
|
|
||||||
// Defaulting of cursor, tooltip, and status if there is no handle,
|
|
||||||
// or if the handle does not specify them
|
|
||||||
const auto preview = newCell->DefaultPreview( tpmState, GetProject() );
|
|
||||||
if (!pCursor)
|
|
||||||
pCursor = preview.cursor;
|
|
||||||
if (status.empty())
|
|
||||||
status = preview.message;
|
|
||||||
if (tooltip.empty())
|
|
||||||
tooltip = preview.tooltip;
|
|
||||||
}
|
|
||||||
if (!pCursor) {
|
|
||||||
// Ultimate default cursor
|
|
||||||
static wxCursor defaultCursor{ wxCURSOR_DEFAULT };
|
|
||||||
pCursor = &defaultCursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateStatusMessage(status);
|
|
||||||
|
|
||||||
#if wxUSE_TOOLTIPS
|
|
||||||
if (tooltip != GetToolTipText()) {
|
|
||||||
// Unset first, by analogy with AButton
|
|
||||||
UnsetToolTip();
|
|
||||||
SetToolTip(tooltip);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (pCursor)
|
|
||||||
SetCursor( *pCursor );
|
|
||||||
|
|
||||||
ProcessUIHandleResult(
|
|
||||||
newCell.get(), newCell.get(), refreshCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackPanel::UpdateStatusMessage( const wxString &st )
|
void TrackPanel::UpdateStatusMessage( const wxString &st )
|
||||||
{
|
{
|
||||||
auto status = st;
|
auto status = st;
|
||||||
@ -987,62 +721,6 @@ void TrackPanel::UpdateStatusMessage( const wxString &st )
|
|||||||
mListener->TP_DisplayStatusMessage(status);
|
mListener->TP_DisplayStatusMessage(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CellularPanel::HasRotation()
|
|
||||||
{
|
|
||||||
// Is there a nontrivial TAB key rotation?
|
|
||||||
if ( mTargets.size() > 1 )
|
|
||||||
return true;
|
|
||||||
auto target = Target();
|
|
||||||
return target && target->HasRotation();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CellularPanel::HasEscape()
|
|
||||||
{
|
|
||||||
if (IsMouseCaptured())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (mTarget + 1 == mTargets.size() &&
|
|
||||||
Target() &&
|
|
||||||
!Target()->HasEscape())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return mTargets.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CellularPanel::ChangeTarget(bool forward, bool cycle)
|
|
||||||
{
|
|
||||||
auto size = mTargets.size();
|
|
||||||
|
|
||||||
auto target = Target();
|
|
||||||
if (target && target->HasRotation()) {
|
|
||||||
if(target->Rotate(forward))
|
|
||||||
return true;
|
|
||||||
else if (cycle && (size == 1 || IsMouseCaptured())) {
|
|
||||||
// Rotate through the states of this target only.
|
|
||||||
target->Enter(forward);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cycle &&
|
|
||||||
((forward && mTarget + 1 == size) ||
|
|
||||||
(!forward && mTarget == 0)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (size > 1) {
|
|
||||||
if (forward)
|
|
||||||
++mTarget;
|
|
||||||
else
|
|
||||||
mTarget += size - 1;
|
|
||||||
mTarget %= size;
|
|
||||||
if (Target())
|
|
||||||
Target()->Enter(forward);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackPanel::UpdateSelectionDisplay()
|
void TrackPanel::UpdateSelectionDisplay()
|
||||||
{
|
{
|
||||||
// Full refresh since the label area may need to indicate
|
// Full refresh since the label area may need to indicate
|
||||||
@ -1101,12 +779,6 @@ void TrackPanel::MessageForScreenReader(const wxString& message)
|
|||||||
mAx->MessageForScreenReader(message);
|
mAx->MessageForScreenReader(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines if a modal tool is active
|
|
||||||
bool CellularPanel::IsMouseCaptured()
|
|
||||||
{
|
|
||||||
return mUIHandle != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackPanel::UpdateViewIfNoTracks()
|
void TrackPanel::UpdateViewIfNoTracks()
|
||||||
{
|
{
|
||||||
if (mTracks->empty())
|
if (mTracks->empty())
|
||||||
@ -1167,11 +839,6 @@ void TrackPanel::OnTrackListDeletion(wxCommandEvent & e)
|
|||||||
e.Skip();
|
e.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellularPanel::OnContextMenu(wxContextMenuEvent & WXUNUSED(event))
|
|
||||||
{
|
|
||||||
DoContextMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TrackInfo::TCPLine {
|
struct TrackInfo::TCPLine {
|
||||||
using DrawFunction = void (*)(
|
using DrawFunction = void (*)(
|
||||||
TrackPanelDrawingContext &context,
|
TrackPanelDrawingContext &context,
|
||||||
@ -1360,85 +1027,6 @@ bool TrackInfo::HideTopItem( const wxRect &rect, const wxRect &subRect,
|
|||||||
return subRect.y + subRect.height - allowance >= rect.y + limit;
|
return subRect.y + subRect.height - allowance >= rect.y + limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle mouse wheel rotation (for zoom in/out, vertical and horizontal scrolling)
|
|
||||||
void CellularPanel::HandleWheelRotation( TrackPanelMouseEvent &tpmEvent )
|
|
||||||
{
|
|
||||||
auto pCell = tpmEvent.pCell;
|
|
||||||
if (!pCell)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto &event = tpmEvent.event;
|
|
||||||
double steps {};
|
|
||||||
#if defined(__WXMAC__) && defined(EVT_MAGNIFY)
|
|
||||||
// PRL:
|
|
||||||
// Pinch and spread implemented in wxWidgets 3.1.0, or cherry-picked from
|
|
||||||
// the future in custom build of 3.0.2
|
|
||||||
if (event.Magnify()) {
|
|
||||||
event.SetControlDown(true);
|
|
||||||
steps = 2 * event.GetMagnification();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
steps = event.m_wheelRotation /
|
|
||||||
(event.m_wheelDelta > 0 ? (double)event.m_wheelDelta : 120.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event.GetWheelAxis() == wxMOUSE_WHEEL_HORIZONTAL) {
|
|
||||||
// Two-fingered horizontal swipe on mac is treated like shift-mousewheel
|
|
||||||
event.SetShiftDown(true);
|
|
||||||
// This makes the wave move in the same direction as the fingers, and the scrollbar
|
|
||||||
// thumb moves oppositely
|
|
||||||
steps *= -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
tpmEvent.steps = steps;
|
|
||||||
|
|
||||||
if(!event.HasAnyModifiers()) {
|
|
||||||
// We will later un-skip if we do anything, but if we don't,
|
|
||||||
// propagate the event up for the sake of the scrubber
|
|
||||||
event.Skip();
|
|
||||||
event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned result =
|
|
||||||
pCell->HandleWheelRotation( tpmEvent, GetProject() );
|
|
||||||
ProcessUIHandleResult(
|
|
||||||
pCell.get(), pCell.get(), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CellularPanel::OnCaptureKey(wxCommandEvent & event)
|
|
||||||
{
|
|
||||||
mEnableTab = false;
|
|
||||||
wxKeyEvent *kevent = static_cast<wxKeyEvent *>(event.GetEventObject());
|
|
||||||
const auto code = kevent->GetKeyCode();
|
|
||||||
if ( WXK_ESCAPE != code )
|
|
||||||
HandleInterruptedDrag();
|
|
||||||
|
|
||||||
// Give focused cell precedence
|
|
||||||
const auto t = GetFocusedCell();
|
|
||||||
if (t) {
|
|
||||||
const unsigned refreshResult =
|
|
||||||
t->CaptureKey(*kevent, *mViewInfo, this);
|
|
||||||
ProcessUIHandleResult(t, t, refreshResult);
|
|
||||||
event.Skip(kevent->GetSkipped());
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// Special TAB key handling, but only if the cell didn't capture it
|
|
||||||
if ( !(t && !kevent->GetSkipped()) &&
|
|
||||||
WXK_TAB == code && HasRotation() ) {
|
|
||||||
// Override TAB navigation in wxWidgets, by not skipping
|
|
||||||
event.Skip(false);
|
|
||||||
mEnableTab = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
if (!t)
|
|
||||||
event.Skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackPanel::OnKeyDown(wxKeyEvent & event)
|
void TrackPanel::OnKeyDown(wxKeyEvent & event)
|
||||||
{
|
{
|
||||||
switch (event.GetKeyCode())
|
switch (event.GetKeyCode())
|
||||||
@ -1459,121 +1047,6 @@ void TrackPanel::OnKeyDown(wxKeyEvent & event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellularPanel::OnKeyDown(wxKeyEvent & event)
|
|
||||||
{
|
|
||||||
switch (event.GetKeyCode())
|
|
||||||
{
|
|
||||||
case WXK_ESCAPE:
|
|
||||||
if(HandleEscapeKey(true))
|
|
||||||
// Don't skip the event, eat it so that
|
|
||||||
// AudacityApp does not also stop any playback.
|
|
||||||
return;
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WXK_ALT:
|
|
||||||
case WXK_SHIFT:
|
|
||||||
case WXK_CONTROL:
|
|
||||||
#ifdef __WXOSX__
|
|
||||||
case WXK_RAW_CONTROL:
|
|
||||||
#endif
|
|
||||||
HandleModifierKey();
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
case WXK_TAB:
|
|
||||||
if ( mEnableTab && HasRotation() ) {
|
|
||||||
ChangeTarget( !event.ShiftDown(), true );
|
|
||||||
HandleCursorForPresentMouseState(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto t = GetFocusedCell();
|
|
||||||
|
|
||||||
if (t) {
|
|
||||||
const unsigned refreshResult =
|
|
||||||
t->KeyDown(event, *mViewInfo, this);
|
|
||||||
ProcessUIHandleResult(t, t, refreshResult);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
event.Skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CellularPanel::OnChar(wxKeyEvent & event)
|
|
||||||
{
|
|
||||||
switch (event.GetKeyCode())
|
|
||||||
{
|
|
||||||
case WXK_ESCAPE:
|
|
||||||
case WXK_ALT:
|
|
||||||
case WXK_SHIFT:
|
|
||||||
case WXK_CONTROL:
|
|
||||||
case WXK_PAGEUP:
|
|
||||||
case WXK_PAGEDOWN:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto t = GetFocusedCell();
|
|
||||||
if (t) {
|
|
||||||
const unsigned refreshResult =
|
|
||||||
t->Char(event, *mViewInfo, this);
|
|
||||||
ProcessUIHandleResult(t, t, refreshResult);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
event.Skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CellularPanel::OnKeyUp(wxKeyEvent & event)
|
|
||||||
{
|
|
||||||
bool didSomething = false;
|
|
||||||
switch (event.GetKeyCode())
|
|
||||||
{
|
|
||||||
case WXK_ESCAPE:
|
|
||||||
didSomething = HandleEscapeKey(false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WXK_ALT:
|
|
||||||
case WXK_SHIFT:
|
|
||||||
case WXK_CONTROL:
|
|
||||||
#ifdef __WXOSX__
|
|
||||||
case WXK_RAW_CONTROL:
|
|
||||||
#endif
|
|
||||||
HandleModifierKey();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (didSomething)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto t = GetFocusedCell();
|
|
||||||
if (t) {
|
|
||||||
const unsigned refreshResult =
|
|
||||||
t->KeyUp(event, *mViewInfo, this);
|
|
||||||
ProcessUIHandleResult(t, t, refreshResult);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.Skip();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Should handle the case when the mouse capture is lost.
|
|
||||||
void CellularPanel::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
|
|
||||||
{
|
|
||||||
ClearTargets();
|
|
||||||
|
|
||||||
// This is bad. We are lying abou the event by saying it is a mouse up.
|
|
||||||
wxMouseEvent e(wxEVT_LEFT_UP);
|
|
||||||
e.SetId( kCaptureLostEventId );
|
|
||||||
|
|
||||||
e.m_x = mMouseMostRecentX;
|
|
||||||
e.m_y = mMouseMostRecentY;
|
|
||||||
|
|
||||||
OnMouseEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TrackPanel::OnMouseEvent(wxMouseEvent & event)
|
void TrackPanel::OnMouseEvent(wxMouseEvent & event)
|
||||||
{
|
{
|
||||||
if (event.LeftDown()) {
|
if (event.LeftDown()) {
|
||||||
@ -1601,195 +1074,6 @@ void TrackPanel::OnMouseEvent(wxMouseEvent & event)
|
|||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This handles just generic mouse events. Then, based
|
|
||||||
/// on our current state, we forward the mouse events to
|
|
||||||
/// various interested parties.
|
|
||||||
void CellularPanel::OnMouseEvent(wxMouseEvent & event)
|
|
||||||
try
|
|
||||||
{
|
|
||||||
const auto foundCell = FindCell( event.m_x, event.m_y );
|
|
||||||
auto &rect = foundCell.rect;
|
|
||||||
auto &pCell = foundCell.pCell;
|
|
||||||
|
|
||||||
const auto size = GetSize();
|
|
||||||
TrackPanelMouseEvent tpmEvent{ event, rect, size, pCell };
|
|
||||||
|
|
||||||
#if defined(__WXMAC__) && defined(EVT_MAGNIFY)
|
|
||||||
// PRL:
|
|
||||||
// Pinch and spread implemented in wxWidgets 3.1.0, or cherry-picked from
|
|
||||||
// the future in custom build of 3.0.2
|
|
||||||
if (event.Magnify()) {
|
|
||||||
HandleWheelRotation( tpmEvent );
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// If a mouse event originates from a keyboard context menu event then
|
|
||||||
// event.GetPosition() == wxDefaultPosition. wxContextMenu events are handled in
|
|
||||||
// CellularPanel::OnContextMenu(), and therefore associated mouse events are ignored here.
|
|
||||||
// Not ignoring them was causing bug 613: the mouse events were interpreted as clicking
|
|
||||||
// outside the tracks.
|
|
||||||
if (event.GetPosition() == wxDefaultPosition && (event.RightDown() || event.RightUp())) {
|
|
||||||
event.Skip();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.m_wheelRotation != 0)
|
|
||||||
HandleWheelRotation( tpmEvent );
|
|
||||||
|
|
||||||
if (event.LeftDown() || event.LeftIsDown() || event.Moving()) {
|
|
||||||
// Skip, even if we do something, so that the left click or drag
|
|
||||||
// may have an additional effect in the scrubber.
|
|
||||||
event.Skip();
|
|
||||||
event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
mMouseMostRecentX = event.m_x;
|
|
||||||
mMouseMostRecentY = event.m_y;
|
|
||||||
|
|
||||||
if (event.LeftDown()) {
|
|
||||||
// The activate event is used to make the
|
|
||||||
// parent window 'come alive' if it didn't have focus.
|
|
||||||
wxActivateEvent e;
|
|
||||||
GetParent()->GetEventHandler()->ProcessEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.ButtonDown()) {
|
|
||||||
SetFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.Leaving())
|
|
||||||
{
|
|
||||||
if ( !mUIHandle )
|
|
||||||
ClearTargets();
|
|
||||||
|
|
||||||
auto buttons =
|
|
||||||
// Bug 1325: button state in Leaving events is unreliable on Mac.
|
|
||||||
// Poll the global state instead.
|
|
||||||
// event.ButtonIsDown(wxMOUSE_BTN_ANY);
|
|
||||||
::wxGetMouseState().ButtonIsDown(wxMOUSE_BTN_ANY);
|
|
||||||
|
|
||||||
if(!buttons) {
|
|
||||||
CancelDragging();
|
|
||||||
|
|
||||||
#if defined(__WXMAC__)
|
|
||||||
|
|
||||||
// We must install the cursor ourselves since the window under
|
|
||||||
// the mouse is no longer this one and wx2.8.12 makes that check.
|
|
||||||
// Should re-evaluate with wx3.
|
|
||||||
wxSTANDARD_CURSOR->MacInstall();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mUIHandle) {
|
|
||||||
auto pClickedCell = mpClickedCell.lock();
|
|
||||||
if (event.Dragging()) {
|
|
||||||
// UIHANDLE DRAG
|
|
||||||
// copy shared_ptr for safety, as in HandleClick
|
|
||||||
auto handle = mUIHandle;
|
|
||||||
const UIHandle::Result refreshResult =
|
|
||||||
handle->Drag( tpmEvent, GetProject() );
|
|
||||||
ProcessUIHandleResult
|
|
||||||
(pClickedCell.get(), pCell.get(), refreshResult);
|
|
||||||
mMouseOverUpdateFlags |= refreshResult;
|
|
||||||
if (refreshResult & RefreshCode::Cancelled) {
|
|
||||||
// Drag decided to abort itself
|
|
||||||
mUIHandle.reset(), handle.reset(), ClearTargets();
|
|
||||||
mpClickedCell.reset();
|
|
||||||
Uncapture( &event );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
UpdateMouseState(event);
|
|
||||||
TrackPanelMouseState tpmState{ mLastMouseState, rect, pCell };
|
|
||||||
HandleMotion( tpmState );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (event.ButtonUp()) {
|
|
||||||
// UIHANDLE RELEASE
|
|
||||||
unsigned moreFlags = mMouseOverUpdateFlags;
|
|
||||||
UIHandle::Result refreshResult =
|
|
||||||
mUIHandle->Release( tpmEvent, GetProject(), this );
|
|
||||||
ProcessUIHandleResult
|
|
||||||
(pClickedCell.get(), pCell.get(),
|
|
||||||
refreshResult | moreFlags);
|
|
||||||
mUIHandle.reset(), ClearTargets();
|
|
||||||
mpClickedCell.reset();
|
|
||||||
// will also Uncapture() below
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( event.GetEventType() == wxEVT_MOTION )
|
|
||||||
// Update status message and cursor, not during drag
|
|
||||||
// consider it not a drag, even if button is down during motion, if
|
|
||||||
// mUIHandle is null, as it becomes during interrupted drag
|
|
||||||
// (e.g. by hitting space to play while dragging an envelope point)
|
|
||||||
HandleMotion( event );
|
|
||||||
else if ( event.ButtonDown() || event.ButtonDClick() )
|
|
||||||
HandleClick( tpmEvent );
|
|
||||||
|
|
||||||
if (event.ButtonDown() && IsMouseCaptured()) {
|
|
||||||
if (!HasCapture())
|
|
||||||
CaptureMouse();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.ButtonUp())
|
|
||||||
Uncapture();
|
|
||||||
}
|
|
||||||
catch( ... )
|
|
||||||
{
|
|
||||||
// Abort any dragging, as if by hitting Esc
|
|
||||||
if ( CancelDragging() )
|
|
||||||
;
|
|
||||||
else {
|
|
||||||
Uncapture();
|
|
||||||
Refresh(false);
|
|
||||||
}
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CellularPanel::HandleClick( const TrackPanelMouseEvent &tpmEvent )
|
|
||||||
{
|
|
||||||
auto pCell = tpmEvent.pCell;
|
|
||||||
|
|
||||||
// Do hit test once more, in case the button really pressed was not the
|
|
||||||
// one "anticipated."
|
|
||||||
{
|
|
||||||
TrackPanelMouseState tpmState{
|
|
||||||
tpmEvent.event,
|
|
||||||
tpmEvent.rect,
|
|
||||||
tpmEvent.pCell
|
|
||||||
};
|
|
||||||
HandleMotion( tpmState );
|
|
||||||
}
|
|
||||||
|
|
||||||
mUIHandle = Target();
|
|
||||||
|
|
||||||
if (mUIHandle) {
|
|
||||||
// UIHANDLE CLICK
|
|
||||||
// Make another shared pointer to the handle, in case recursive
|
|
||||||
// event dispatching otherwise tries to delete the handle.
|
|
||||||
auto handle = mUIHandle;
|
|
||||||
UIHandle::Result refreshResult =
|
|
||||||
handle->Click( tpmEvent, GetProject() );
|
|
||||||
if (refreshResult & RefreshCode::Cancelled)
|
|
||||||
mUIHandle.reset(), handle.reset(), ClearTargets();
|
|
||||||
else {
|
|
||||||
mpClickedCell = pCell;
|
|
||||||
|
|
||||||
// Perhaps the clicked handle wants to update cursor and state message
|
|
||||||
// after a click.
|
|
||||||
TrackPanelMouseState tpmState{
|
|
||||||
tpmEvent.event,
|
|
||||||
tpmEvent.rect,
|
|
||||||
tpmEvent.pCell
|
|
||||||
};
|
|
||||||
HandleMotion( tpmState );
|
|
||||||
}
|
|
||||||
ProcessUIHandleResult(
|
|
||||||
pCell.get(), pCell.get(), refreshResult);
|
|
||||||
mMouseOverUpdateFlags |= refreshResult;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double TrackPanel::GetMostRecentXPos()
|
double TrackPanel::GetMostRecentXPos()
|
||||||
{
|
{
|
||||||
return mViewInfo->PositionToTime(MostRecentXCoord(), GetLabelWidth());
|
return mViewInfo->PositionToTime(MostRecentXCoord(), GetLabelWidth());
|
||||||
@ -2628,26 +1912,6 @@ void TrackPanel::OnTrackMenu(Track *t)
|
|||||||
CellularPanel::DoContextMenu( t );
|
CellularPanel::DoContextMenu( t );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellularPanel::DoContextMenu( TrackPanelCell *pCell )
|
|
||||||
{
|
|
||||||
if( !pCell ) {
|
|
||||||
pCell = GetFocusedCell();
|
|
||||||
if( !pCell )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto delegate = pCell->ContextMenuDelegate();
|
|
||||||
if (!delegate)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto rect = FindRect( *delegate );
|
|
||||||
const UIHandle::Result refreshResult =
|
|
||||||
delegate->DoContextMenu(rect, this, NULL);
|
|
||||||
|
|
||||||
// To do: use safer shared_ptr to pCell
|
|
||||||
ProcessUIHandleResult(pCell, pCell, refreshResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
Track * TrackPanel::GetFirstSelectedTrack()
|
Track * TrackPanel::GetFirstSelectedTrack()
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -2944,20 +2208,6 @@ void TrackPanel::SetFocusedTrack( Track *t )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellularPanel::OnSetFocus(wxFocusEvent & WXUNUSED(event))
|
|
||||||
{
|
|
||||||
SetFocusedCell();
|
|
||||||
}
|
|
||||||
|
|
||||||
void CellularPanel::OnKillFocus(wxFocusEvent & WXUNUSED(event))
|
|
||||||
{
|
|
||||||
if (AudacityProject::HasKeyboardCapture(this))
|
|
||||||
{
|
|
||||||
AudacityProject::ReleaseKeyboard(this);
|
|
||||||
}
|
|
||||||
Refresh( false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|
||||||
TrackInfo code is destined to move out of this file.
|
TrackInfo code is destined to move out of this file.
|
||||||
|
133
src/TrackPanel.h
133
src/TrackPanel.h
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "SelectedRegion.h"
|
#include "SelectedRegion.h"
|
||||||
|
|
||||||
#include "widgets/OverlayPanel.h"
|
#include "CellularPanel.h"
|
||||||
|
|
||||||
#include "SelectionState.h"
|
#include "SelectionState.h"
|
||||||
|
|
||||||
@ -34,7 +34,6 @@ class SpectrumAnalyst;
|
|||||||
class Track;
|
class Track;
|
||||||
class TrackList;
|
class TrackList;
|
||||||
class TrackPanel;
|
class TrackPanel;
|
||||||
class TrackPanelCell;
|
|
||||||
class TrackArtist;
|
class TrackArtist;
|
||||||
class Ruler;
|
class Ruler;
|
||||||
class SnapManager;
|
class SnapManager;
|
||||||
@ -43,20 +42,13 @@ class LWSlider;
|
|||||||
class ControlToolBar; //Needed because state of controls can affect what gets drawn.
|
class ControlToolBar; //Needed because state of controls can affect what gets drawn.
|
||||||
class ToolsToolBar; //Needed because state of controls can affect what gets drawn.
|
class ToolsToolBar; //Needed because state of controls can affect what gets drawn.
|
||||||
class MixerBoard;
|
class MixerBoard;
|
||||||
class AudacityProject;
|
|
||||||
|
|
||||||
class TrackPanelAx;
|
class TrackPanelAx;
|
||||||
class TrackPanelCellIterator;
|
class TrackPanelCellIterator;
|
||||||
struct TrackPanelMouseEvent;
|
|
||||||
struct TrackPanelMouseState;
|
|
||||||
|
|
||||||
class ViewInfo;
|
|
||||||
|
|
||||||
class NoteTrack;
|
class NoteTrack;
|
||||||
class WaveTrack;
|
class WaveTrack;
|
||||||
class WaveClip;
|
class WaveClip;
|
||||||
class UIHandle;
|
|
||||||
using UIHandlePtr = std::shared_ptr<UIHandle>;
|
|
||||||
|
|
||||||
// Declared elsewhere, to reduce compilation dependencies
|
// Declared elsewhere, to reduce compilation dependencies
|
||||||
class TrackPanelListener;
|
class TrackPanelListener;
|
||||||
@ -242,127 +234,6 @@ private:
|
|||||||
const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
|
const int DragThreshold = 3;// Anything over 3 pixels is a drag, else a click.
|
||||||
|
|
||||||
|
|
||||||
// This class manages a panel divided into a number of sub-rectangles called
|
|
||||||
// cells, that each implement hit tests returning click-drag-release handler
|
|
||||||
// objects, and other services.
|
|
||||||
// It has no dependency on the Track class.
|
|
||||||
class AUDACITY_DLL_API CellularPanel : public OverlayPanel {
|
|
||||||
public:
|
|
||||||
CellularPanel(wxWindow * parent, wxWindowID id,
|
|
||||||
const wxPoint & pos,
|
|
||||||
const wxSize & size,
|
|
||||||
ViewInfo *viewInfo,
|
|
||||||
// default as for wxPanel:
|
|
||||||
long style = wxTAB_TRAVERSAL | wxNO_BORDER)
|
|
||||||
: OverlayPanel(parent, id, pos, size, style)
|
|
||||||
, mViewInfo( viewInfo )
|
|
||||||
{}
|
|
||||||
|
|
||||||
// Overridables:
|
|
||||||
|
|
||||||
virtual AudacityProject *GetProject() const = 0;
|
|
||||||
|
|
||||||
// Find track info by coordinate
|
|
||||||
struct FoundCell {
|
|
||||||
std::shared_ptr<TrackPanelCell> pCell;
|
|
||||||
wxRect rect;
|
|
||||||
};
|
|
||||||
virtual FoundCell FindCell(int mouseX, int mouseY) = 0;
|
|
||||||
virtual wxRect FindRect(const TrackPanelCell &cell) = 0;
|
|
||||||
virtual TrackPanelCell *GetFocusedCell() = 0;
|
|
||||||
virtual void SetFocusedCell() = 0;
|
|
||||||
|
|
||||||
virtual void ProcessUIHandleResult
|
|
||||||
(TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell,
|
|
||||||
unsigned refreshResult) = 0;
|
|
||||||
|
|
||||||
virtual void UpdateStatusMessage( const wxString & ) = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
UIHandlePtr Target()
|
|
||||||
{
|
|
||||||
if (mTargets.size())
|
|
||||||
return mTargets[mTarget];
|
|
||||||
else
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsMouseCaptured();
|
|
||||||
|
|
||||||
wxCoord MostRecentXCoord() const { return mMouseMostRecentX; }
|
|
||||||
|
|
||||||
void HandleCursorForPresentMouseState(bool doHit = true);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool HasEscape();
|
|
||||||
bool CancelDragging();
|
|
||||||
void ClearTargets()
|
|
||||||
{
|
|
||||||
// Forget the rotation of hit test candidates when the mouse moves from
|
|
||||||
// cell to cell or outside of the panel entirely.
|
|
||||||
mLastCell.reset();
|
|
||||||
mTargets.clear();
|
|
||||||
mTarget = 0;
|
|
||||||
mMouseOverUpdateFlags = 0;
|
|
||||||
}
|
|
||||||
void DoContextMenu( TrackPanelCell *pCell = nullptr );
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool HasRotation();
|
|
||||||
bool ChangeTarget(bool forward, bool cycle);
|
|
||||||
|
|
||||||
void OnMouseEvent(wxMouseEvent & event);
|
|
||||||
void OnCaptureLost(wxMouseCaptureLostEvent & event);
|
|
||||||
void OnCaptureKey(wxCommandEvent & event);
|
|
||||||
void OnKeyDown(wxKeyEvent & event);
|
|
||||||
void OnChar(wxKeyEvent & event);
|
|
||||||
void OnKeyUp(wxKeyEvent & event);
|
|
||||||
|
|
||||||
void OnSetFocus(wxFocusEvent & event);
|
|
||||||
void OnKillFocus(wxFocusEvent & event);
|
|
||||||
|
|
||||||
void OnContextMenu(wxContextMenuEvent & event);
|
|
||||||
|
|
||||||
void HandleInterruptedDrag();
|
|
||||||
void Uncapture( wxMouseState *pState = nullptr );
|
|
||||||
bool HandleEscapeKey(bool down);
|
|
||||||
void UpdateMouseState(const wxMouseState &state);
|
|
||||||
void HandleModifierKey();
|
|
||||||
|
|
||||||
void HandleClick( const TrackPanelMouseEvent &tpmEvent );
|
|
||||||
void HandleWheelRotation( TrackPanelMouseEvent &tpmEvent );
|
|
||||||
|
|
||||||
void HandleMotion( wxMouseState &state, bool doHit = true );
|
|
||||||
void HandleMotion
|
|
||||||
( const TrackPanelMouseState &tpmState, bool doHit = true );
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
ViewInfo *mViewInfo;
|
|
||||||
|
|
||||||
private:
|
|
||||||
UIHandlePtr mUIHandle;
|
|
||||||
|
|
||||||
std::weak_ptr<TrackPanelCell> mLastCell;
|
|
||||||
std::vector<UIHandlePtr> mTargets;
|
|
||||||
size_t mTarget {};
|
|
||||||
unsigned mMouseOverUpdateFlags{};
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// To do: make a drawing method and make this private
|
|
||||||
wxMouseState mLastMouseState;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int mMouseMostRecentX;
|
|
||||||
int mMouseMostRecentY;
|
|
||||||
|
|
||||||
std::weak_ptr<TrackPanelCell> mpClickedCell;
|
|
||||||
|
|
||||||
bool mEnableTab{};
|
|
||||||
|
|
||||||
DECLARE_EVENT_TABLE()
|
|
||||||
};
|
|
||||||
|
|
||||||
class AUDACITY_DLL_API TrackPanel final : public CellularPanel {
|
class AUDACITY_DLL_API TrackPanel final : public CellularPanel {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -606,7 +477,7 @@ protected:
|
|||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
|
|
||||||
void ProcessUIHandleResult
|
void ProcessUIHandleResult
|
||||||
(TrackPanelCell *pClickedCell, TrackPanelCell *pLatestCell,
|
(TrackPanelCell *pClickedTrack, TrackPanelCell *pLatestCell,
|
||||||
unsigned refreshResult) override;
|
unsigned refreshResult) override;
|
||||||
|
|
||||||
void UpdateStatusMessage( const wxString &status ) override;
|
void UpdateStatusMessage( const wxString &status ) override;
|
||||||
|
@ -138,6 +138,7 @@
|
|||||||
<ClCompile Include="..\..\..\src\Benchmark.cpp" />
|
<ClCompile Include="..\..\..\src\Benchmark.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\BlockFile.cpp" />
|
<ClCompile Include="..\..\..\src\BlockFile.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\blockfile\NotYetAvailableException.cpp" />
|
<ClCompile Include="..\..\..\src\blockfile\NotYetAvailableException.cpp" />
|
||||||
|
<ClCompile Include="..\..\..\src\CellularPanel.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\commands\AudacityCommand.cpp" />
|
<ClCompile Include="..\..\..\src\commands\AudacityCommand.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\commands\CommandContext.cpp" />
|
<ClCompile Include="..\..\..\src\commands\CommandContext.cpp" />
|
||||||
<ClCompile Include="..\..\..\src\commands\CommandTargets.cpp" />
|
<ClCompile Include="..\..\..\src\commands\CommandTargets.cpp" />
|
||||||
@ -481,6 +482,7 @@
|
|||||||
<ClInclude Include="..\..\..\src\Benchmark.h" />
|
<ClInclude Include="..\..\..\src\Benchmark.h" />
|
||||||
<ClInclude Include="..\..\..\src\BlockFile.h" />
|
<ClInclude Include="..\..\..\src\BlockFile.h" />
|
||||||
<ClInclude Include="..\..\..\src\blockfile\NotYetAvailableException.h" />
|
<ClInclude Include="..\..\..\src\blockfile\NotYetAvailableException.h" />
|
||||||
|
<ClInclude Include="..\..\..\src\CellularPanel.h" />
|
||||||
<ClInclude Include="..\..\..\src\commands\AudacityCommand.h" />
|
<ClInclude Include="..\..\..\src\commands\AudacityCommand.h" />
|
||||||
<ClInclude Include="..\..\..\src\commands\CommandContext.h" />
|
<ClInclude Include="..\..\..\src\commands\CommandContext.h" />
|
||||||
<ClInclude Include="..\..\..\src\commands\CommandFlag.h" />
|
<ClInclude Include="..\..\..\src\commands\CommandFlag.h" />
|
||||||
|
@ -1082,6 +1082,9 @@
|
|||||||
<ClCompile Include="..\..\..\src\widgets\WindowAccessible.cpp">
|
<ClCompile Include="..\..\..\src\widgets\WindowAccessible.cpp">
|
||||||
<Filter>src\widgets</Filter>
|
<Filter>src\widgets</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\..\src\CellularPanel.cpp">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\..\src\AboutDialog.h">
|
<ClInclude Include="..\..\..\src\AboutDialog.h">
|
||||||
@ -2158,6 +2161,9 @@
|
|||||||
<ClInclude Include="..\..\..\src\widgets\WindowAccessible.h">
|
<ClInclude Include="..\..\..\src\widgets\WindowAccessible.h">
|
||||||
<Filter>src\widgets</Filter>
|
<Filter>src\widgets</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\..\src\CellularPanel.h">
|
||||||
|
<Filter>src</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Image Include="..\..\audacity.ico">
|
<Image Include="..\..\audacity.ico">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user