Audacity 3.2.0
TrackPanelResizeHandle.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5TrackPanelResizeHandle.cpp
6
7Paul Licameli split from TrackPanel.cpp
8
9**********************************************************************/
10
11
13
14#include <wx/cursor.h>
15#include <wx/event.h>
16#include <wx/translation.h>
17
18#include "HitTestResult.h"
19#include "ProjectHistory.h"
20#include "RefreshCode.h"
21#include "Track.h"
23#include "tracks/ui/TrackView.h"
24
26{
27 // TODO: more-than-two-channels-message
28
29 static wxCursor resizeCursor{ wxCURSOR_SIZENS };
30
32 // Check to see whether it is the first channel of a stereo track
33 if (bLinked) {
34 // If we are in the label we got here 'by mistake' and we're
35 // not actually in the resize area at all. (The resize area
36 // is shorter when it is between stereo tracks).
37
38 return {
39 XO(
40"Click and drag to adjust relative size of stereo tracks, double-click to make heights equal"),
41 &resizeCursor
42 };
43 }
44 else {
45 return {
46 XO("Click and drag to resize the track."),
47 &resizeCursor
48 };
49 }
50}
51
53{
54}
55
57 const TrackPanelMouseEvent &evt, AudacityProject *pProject )
58{
59 using namespace RefreshCode;
60 if ( evt.event.LeftDClick() && mMode == IsResizingBetweenLinkedTracks ) {
61 auto &tracks = TrackList::Get( *pProject );
62 auto pTrack = tracks.Lock(mpTrack);
63 if (pTrack &&
64 !TrackView::Get(*pTrack).GetMinimized()) {
65 auto range = TrackList::Channels( pTrack.get() );
66 auto size = range.size();
67 auto height = range.sum( [](const Track *pTrack){
68 return TrackView::Get(*pTrack).GetHeight(); } );
69 int ii = 1;
70 int coord = 0;
71 for ( const auto channel : range ) {
72 int newCoord = ((double)ii++ /size) * height;
73 TrackView::Get(*channel).SetExpandedHeight( newCoord - coord );
74 coord = newCoord;
75 }
76 ProjectHistory::Get( *pProject ).ModifyState(false);
77 // Do not start a drag
78 return Cancelled | RefreshAll;
79 }
80 }
81 return RefreshNone;
82}
83
85( const std::shared_ptr<Track> &track, int y )
86 : mpTrack{ track }
87 , mMouseClickY( y )
88{
89 // TODO: more-than-two-channels
90
91 //STM: Determine whether we should rescale one or two tracks
92 auto channels = TrackList::Channels(track.get());
93 auto last = *channels.rbegin();
94 auto &lastView = TrackView::Get( *last );
95 mInitialTrackHeight = lastView.GetHeight();
96 mInitialExpandedHeight = lastView.GetExpandedHeight();
97 mInitialMinimized = lastView.GetMinimized();
98
99 if (channels.size() > 1) {
100 auto first = *channels.begin();
101 auto &firstView = TrackView::Get( *first );
102
103 mInitialUpperTrackHeight = firstView.GetHeight();
104 mInitialUpperExpandedHeight = firstView.GetExpandedHeight();
105
106 if (track.get() == *channels.rbegin())
107 // capturedTrack is the lowest track
109 else
110 // capturedTrack is not the lowest track
112 }
113 else
115}
116
118(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
119{
120 auto &tracks = TrackList::Get( *pProject );
121 auto pTrack = tracks.Lock(mpTrack);
122 if ( !pTrack )
124
125 auto &view = TrackView::Get( *pTrack );
126
127 const wxMouseEvent &event = evt.event;
128
129 int delta = (event.m_y - mMouseClickY);
130
131 // On first drag, jump out of minimized mode. Initial height
132 // will be height of minimized track.
133 //
134 // This used to be in HandleResizeClick(), but simply clicking
135 // on a resize border would switch the minimized state.
136 auto &data = TrackView::Get( *pTrack );
137 if (data.GetMinimized()) {
138 auto channels = TrackList::Channels( pTrack.get() );
139 for (auto channel : channels) {
140 auto &channelView = TrackView::Get( *channel );
141 channelView.SetExpandedHeight(channelView.GetHeight());
142 channelView.SetMinimized( false );
143 }
144
145 if (channels.size() > 1) {
146 // Initial values must be reset since they weren't based on the
147 // minimized heights.
148 auto &channelView = TrackView::Get( **channels.begin() );
149 mInitialUpperTrackHeight = channelView.GetHeight();
150 mInitialTrackHeight = channelView.GetHeight();
151 }
152 }
153
154 // Common pieces of code for MONO_WAVE_PAN and otherwise.
155 auto doResizeBelow = [&] (Track *prev, bool WXUNUSED(vStereo)) {
156 // TODO: more-than-two-channels
157
158 auto &prevView = TrackView::Get( *prev );
159
160 double proportion = static_cast < double >(mInitialTrackHeight)
162
163 int newTrackHeight = static_cast < int >
164 (mInitialTrackHeight + delta * proportion);
165
166 int newUpperTrackHeight = static_cast < int >
167 (mInitialUpperTrackHeight + delta * (1.0 - proportion));
168
169 //make sure neither track is smaller than its minimum height
170 if (newTrackHeight < view.GetMinimizedHeight())
171 newTrackHeight = view.GetMinimizedHeight();
172 if (newUpperTrackHeight < prevView.GetMinimizedHeight())
173 newUpperTrackHeight = prevView.GetMinimizedHeight();
174
175 view.SetExpandedHeight(newTrackHeight);
176 prevView.SetExpandedHeight(newUpperTrackHeight);
177 };
178
179 auto doResizeBetween = [&] (Track *next, bool WXUNUSED(vStereo)) {
180 // TODO: more-than-two-channels
181
182 auto &nextView = TrackView::Get( *next );
183 int newUpperTrackHeight = mInitialUpperTrackHeight + delta;
184 int newTrackHeight = mInitialTrackHeight - delta;
185
186 // make sure neither track is smaller than its minimum height
187 if (newTrackHeight < nextView.GetMinimizedHeight()) {
188 newTrackHeight = nextView.GetMinimizedHeight();
189 newUpperTrackHeight =
190 mInitialUpperTrackHeight + mInitialTrackHeight - nextView.GetMinimizedHeight();
191 }
192 if (newUpperTrackHeight < view.GetMinimizedHeight()) {
193 newUpperTrackHeight = view.GetMinimizedHeight();
194 newTrackHeight =
195 mInitialUpperTrackHeight + mInitialTrackHeight - view.GetMinimizedHeight();
196 }
197
198 view.SetExpandedHeight(newUpperTrackHeight);
199 nextView.SetExpandedHeight(newTrackHeight);
200 };
201
202 auto doResize = [&] {
203 int newTrackHeight = mInitialTrackHeight + delta;
204 if (newTrackHeight < view.GetMinimizedHeight())
205 newTrackHeight = view.GetMinimizedHeight();
206 view.SetExpandedHeight(newTrackHeight);
207 };
208
209 //STM: We may be dragging one or two (stereo) tracks.
210 // If two, resize proportionally if we are dragging the lower track, and
211 // adjust compensatively if we are dragging the upper track.
212
213 switch( mMode )
214 {
216 {
217 auto prev = * -- tracks.Find(pTrack.get());
218 doResizeBelow(prev, false);
219 break;
220 }
222 {
223 auto next = * ++ tracks.Find(pTrack.get());
224 doResizeBetween(next, false);
225 break;
226 }
227 case IsResizing:
228 {
229 doResize();
230 break;
231 }
232 default:
233 // don't refresh in this case.
235 }
236
238}
239
242{
244}
245
247(const TrackPanelMouseEvent &, AudacityProject *pProject,
248 wxWindow *)
249{
256 ProjectHistory::Get( *pProject ).ModifyState(false);
258}
259
261{
262 auto &tracks = TrackList::Get( *pProject );
263 auto pTrack = tracks.Lock(mpTrack);
264 if ( !pTrack )
266
267
268 switch (mMode) {
269 case IsResizing:
270 {
271 auto &view = TrackView::Get( *pTrack );
272 view.SetExpandedHeight(mInitialExpandedHeight);
273 view.SetMinimized( mInitialMinimized );
274 }
275 break;
277 {
278 Track *const next = * ++ tracks.Find(pTrack.get());
279 auto
280 &view = TrackView::Get( *pTrack ), &nextView = TrackView::Get( *next );
281 view.SetExpandedHeight(mInitialUpperExpandedHeight);
282 view.SetMinimized( mInitialMinimized );
283 nextView.SetExpandedHeight(mInitialExpandedHeight);
284 nextView.SetMinimized( mInitialMinimized );
285 }
286 break;
288 {
289 Track *const prev = * -- tracks.Find(pTrack.get());
290 auto
291 &view = TrackView::Get( *pTrack ), &prevView = TrackView::Get( *prev );
292 view.SetExpandedHeight(mInitialExpandedHeight);
293 view.SetMinimized( mInitialMinimized );
294 prevView.SetExpandedHeight(mInitialUpperExpandedHeight);
295 prevView.SetMinimized(mInitialMinimized);
296 }
297 break;
298 }
299
301}
XO("Cut/Copy/Paste")
declares abstract base class Track, TrackList, and iterators over TrackList
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
Subclass * Find(const RegisteredFactory &key)
Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand...
Definition: ClientData.h:333
void ModifyState(bool bWantsAutoSave)
static ProjectHistory & Get(AudacityProject &project)
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:226
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:487
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1544
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
TrackPanelResizeHandle(const TrackPanelResizeHandle &)=delete
static HitTestPreview HitPreview(bool bLinked)
std::weak_ptr< Track > mpTrack
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
Result Cancel(AudacityProject *pProject) override
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
int GetHeight() const
Definition: TrackView.cpp:164
bool GetMinimized() const
Definition: TrackView.h:52
void SetExpandedHeight(int height)
Definition: TrackView.cpp:172
static TrackView & Get(Track &)
Definition: TrackView.cpp:69
unsigned Result
Definition: UIHandle.h:38
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16