Audacity  2.3.1
TrackPanelResizeHandle.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3 Audacity: A Digital Audio Editor
4 
5 TrackPanelResizeHandle.cpp
6 
7 Paul Licameli split from TrackPanel.cpp
8 
9 **********************************************************************/
10 
11 #include "Audacity.h"
12 #include "TrackPanelResizeHandle.h"
13 #include "Experimental.h"
14 
15 #include "MemoryX.h"
16 
17 #include <wx/cursor.h>
18 #include <wx/translation.h>
19 
20 #include "HitTestResult.h"
21 #include "Project.h"
22 #include "RefreshCode.h"
23 #include "Track.h"
24 #include "TrackPanelMouseEvent.h"
26 
28 {
29  // TODO: more-than-two-channels-message
30 
31  static wxCursor resizeCursor{ wxCURSOR_SIZENS };
32 
34  // Check to see whether it is the first channel of a stereo track
35  if (bLinked) {
36  // If we are in the label we got here 'by mistake' and we're
37  // not actually in the resize area at all. (The resize area
38  // is shorter when it is between stereo tracks).
39 
40  return {
41  _("Click and drag to adjust relative size of stereo tracks."),
42  &resizeCursor
43  };
44  }
45  else {
46  return {
47  _("Click and drag to resize the track."),
48  &resizeCursor
49  };
50  }
51 }
52 
54 {
55 }
56 
58 (const TrackPanelMouseEvent &WXUNUSED(evt), AudacityProject *WXUNUSED(pProject))
59 {
61 }
62 
64 ( const std::shared_ptr<Track> &track, int y )
65  : mpTrack{ track }
66  , mMouseClickY( y )
67 {
68  // TODO: more-than-two-channels
69 
70  //STM: Determine whether we should rescale one or two tracks
71  auto channels = TrackList::Channels(track.get());
72  auto last = *channels.rbegin();
73  mInitialTrackHeight = last->GetHeight();
74  mInitialActualHeight = last->GetActualHeight();
75  mInitialMinimized = last->GetMinimized();
76 
77  if (channels.size() > 1) {
78  auto first = *channels.begin();
79 
80  mInitialUpperTrackHeight = first->GetHeight();
81  mInitialUpperActualHeight = first->GetActualHeight();
82 
83  if (track.get() == *channels.rbegin())
84  // capturedTrack is the lowest track
85  mMode = IsResizingBelowLinkedTracks;
86  else
87  // capturedTrack is not the lowest track
88  mMode = IsResizingBetweenLinkedTracks;
89  }
90  else
91  mMode = IsResizing;
92 }
93 
95 (const TrackPanelMouseEvent &evt, AudacityProject *pProject)
96 {
97  auto pTrack = pProject->GetTracks()->Lock(mpTrack);
98  if ( !pTrack )
100 
101  const wxMouseEvent &event = evt.event;
102  TrackList *const tracks = pProject->GetTracks();
103 
104  int delta = (event.m_y - mMouseClickY);
105 
106  // On first drag, jump out of minimized mode. Initial height
107  // will be height of minimized track.
108  //
109  // This used to be in HandleResizeClick(), but simply clicking
110  // on a resize border would switch the minimized state.
111  if (pTrack->GetMinimized()) {
112  auto channels = TrackList::Channels( pTrack.get() );
113  for (auto channel : channels) {
114  channel->SetHeight(channel->GetHeight());
115  channel->SetMinimized(false);
116  }
117 
118  if (channels.size() > 1) {
119  // Initial values must be reset since they weren't based on the
120  // minimized heights.
121  mInitialUpperTrackHeight = (*channels.begin())->GetHeight();
122  mInitialTrackHeight = (*channels.rbegin())->GetHeight();
123  }
124  }
125 
126  // Common pieces of code for MONO_WAVE_PAN and otherwise.
127  auto doResizeBelow = [&] (Track *prev, bool WXUNUSED(vStereo)) {
128  // TODO: more-than-two-channels
129 
130  double proportion = static_cast < double >(mInitialTrackHeight)
131  / (mInitialTrackHeight + mInitialUpperTrackHeight);
132 
133  int newTrackHeight = static_cast < int >
134  (mInitialTrackHeight + delta * proportion);
135 
136  int newUpperTrackHeight = static_cast < int >
137  (mInitialUpperTrackHeight + delta * (1.0 - proportion));
138 
139  //make sure neither track is smaller than its minimum height
140  if (newTrackHeight < pTrack->GetMinimizedHeight())
141  newTrackHeight = pTrack->GetMinimizedHeight();
142  if (newUpperTrackHeight < prev->GetMinimizedHeight())
143  newUpperTrackHeight = prev->GetMinimizedHeight();
144 
145  pTrack->SetHeight(newTrackHeight);
146  prev->SetHeight(newUpperTrackHeight);
147  };
148 
149  auto doResizeBetween = [&] (Track *next, bool WXUNUSED(vStereo)) {
150  // TODO: more-than-two-channels
151 
152  int newUpperTrackHeight = mInitialUpperTrackHeight + delta;
153  int newTrackHeight = mInitialTrackHeight - delta;
154 
155  // make sure neither track is smaller than its minimum height
156  if (newTrackHeight < next->GetMinimizedHeight()) {
157  newTrackHeight = next->GetMinimizedHeight();
158  newUpperTrackHeight =
159  mInitialUpperTrackHeight + mInitialTrackHeight - next->GetMinimizedHeight();
160  }
161  if (newUpperTrackHeight < pTrack->GetMinimizedHeight()) {
162  newUpperTrackHeight = pTrack->GetMinimizedHeight();
163  newTrackHeight =
164  mInitialUpperTrackHeight + mInitialTrackHeight - pTrack->GetMinimizedHeight();
165  }
166 
167  pTrack->SetHeight(newUpperTrackHeight);
168  next->SetHeight(newTrackHeight);
169  };
170 
171  auto doResize = [&] {
172  int newTrackHeight = mInitialTrackHeight + delta;
173  if (newTrackHeight < pTrack->GetMinimizedHeight())
174  newTrackHeight = pTrack->GetMinimizedHeight();
175  pTrack->SetHeight(newTrackHeight);
176  };
177 
178  //STM: We may be dragging one or two (stereo) tracks.
179  // If two, resize proportionally if we are dragging the lower track, and
180  // adjust compensatively if we are dragging the upper track.
181 
182  switch( mMode )
183  {
184  case IsResizingBelowLinkedTracks:
185  {
186  auto prev = * -- tracks->Find(pTrack.get());
187  doResizeBelow(prev, false);
188  break;
189  }
190  case IsResizingBetweenLinkedTracks:
191  {
192  auto next = * ++ tracks->Find(pTrack.get());
193  doResizeBetween(next, false);
194  break;
195  }
196  case IsResizing:
197  {
198  doResize();
199  break;
200  }
201  default:
202  // don't refresh in this case.
204  }
205 
207 }
208 
211 {
212  return HitPreview(mMode == IsResizingBetweenLinkedTracks);
213 }
214 
217  wxWindow *)
218 {
225  pProject->ModifyState(false);
227 }
228 
230 {
231  auto pTrack = pProject->GetTracks()->Lock(mpTrack);
232  if ( !pTrack )
233  return RefreshCode::Cancelled;
234 
235  TrackList *const tracks = pProject->GetTracks();
236 
237  switch (mMode) {
238  case IsResizing:
239  {
240  pTrack->SetHeight(mInitialActualHeight);
241  pTrack->SetMinimized(mInitialMinimized);
242  }
243  break;
245  {
246  Track *const next = * ++ tracks->Find(pTrack.get());
247  pTrack->SetHeight(mInitialUpperActualHeight);
248  pTrack->SetMinimized(mInitialMinimized);
251  }
252  break;
254  {
255  Track *const prev = * -- tracks->Find(pTrack.get());
256  pTrack->SetHeight(mInitialActualHeight);
257  pTrack->SetMinimized(mInitialMinimized);
260  }
261  break;
262  }
263 
265 }
Result Cancel(AudacityProject *pProject) override
void SetHeight(int h)
Definition: Track.cpp:192
auto Find(Track *pTrack) -> TrackIter< TrackType >
Definition: Track.h:1209
virtual int GetMinimizedHeight() const
Definition: Track.cpp:137
void SetMinimized(bool isMinimized)
Definition: Track.cpp:222
std::weak_ptr< Track > mpTrack
TrackPanelResizeHandle(const TrackPanelResizeHandle &)=delete
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
AudacityProject provides the main window, with tools and tracks contained within it.
Definition: Project.h:174
unsigned Result
Definition: UIHandle.h:37
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
HitTestPreview Preview(const TrackPanelMouseState &state, const AudacityProject *pProject) override
Fundamental data object of Audacity, placed in the TrackPanel. Classes derived form it include the Wa...
Definition: Track.h:191
std::shared_ptr< Subclass > Lock(const std::weak_ptr< Subclass > &wTrack)
Definition: Track.h:1435
void ModifyState(bool bWantsAutoSave)
Definition: Project.cpp:4656
static HitTestPreview HitPreview(bool bLinked)
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
TrackList * GetTracks()
Definition: Project.h:209
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1356