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"
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
56std::shared_ptr<const Track> TrackPanelResizeHandle::FindTrack() const
57{
58 return TrackFromChannel(mwChannel.lock());
59}
60
61std::shared_ptr<Channel> TrackPanelResizeHandle::FindChannel()
62{
63 return mwChannel.lock();
64}
65
67 const TrackPanelMouseEvent &evt, AudacityProject *pProject )
68{
69 using namespace RefreshCode;
70 if (evt.event.LeftDClick() && mMode == IsResizingBetweenLinkedTracks) {
71 auto &tracks = TrackList::Get(*pProject);
72 auto theChannel = FindChannel();
73 if (!theChannel)
74 return RefreshNone;
75 auto &view = ChannelView::Get(*theChannel);
76 if (!view.GetMinimized()) {
77 auto range = GetTrack(*theChannel).Channels();
78 auto size = range.size();
79 auto height = range.sum( [](auto pChannel){
80 return ChannelView::Get(*pChannel).GetHeight(); } );
81 int ii = 1;
82 int coord = 0;
83 for (const auto pChannel : range) {
84 int newCoord = ((double)ii++ /size) * height;
85 ChannelView::Get(*pChannel).SetExpandedHeight(newCoord - coord);
86 coord = newCoord;
87 }
88 ProjectHistory::Get( *pProject ).ModifyState(false);
89 // Do not start a drag
90 return Cancelled | RefreshAll;
91 }
92 }
93 return RefreshNone;
94}
95
97 const std::shared_ptr<Channel> &pChannel, int y
98) : mwChannel{ pChannel }
99 , mMouseClickY( y )
100{
101 // TODO: more-than-two-channels
102
103 //STM: Determine whether we should rescale one or two tracks
104 auto channels = GetTrack(*pChannel).Channels();
105 auto last = *channels.rbegin();
106 auto &lastView = ChannelView::Get(*last);
107 mInitialTrackHeight = lastView.GetHeight();
108 mInitialExpandedHeight = lastView.GetExpandedHeight();
109 mInitialMinimized = lastView.GetMinimized();
110
111 if (channels.size() > 1) {
112 auto first = *channels.begin();
113 auto &firstView = ChannelView::Get(*first);
114
115 mInitialUpperTrackHeight = firstView.GetHeight();
116 mInitialUpperExpandedHeight = firstView.GetExpandedHeight();
117
118 if (pChannel == *channels.rbegin())
119 // pChannel is lowest among two or more,
120 // so there is a previous channel
122 else
123 // pChannel is not the lowest among two or more,
124 // so there is a next channel
126 }
127 else
128 // Don't assume there is a next or previous channel
130}
131
133{
134 // Assume channel is last of two
135 // TODO: more-than-two-channels
136 auto channels = GetTrack(channel).Channels();
137 return &**channels.begin();
138}
139
141{
142 // Assume channel is first of two
143 // TODO: more-than-two-channels
144 auto channels = GetTrack(channel).Channels();
145 return &**channels.rbegin();
146}
147
149(const TrackPanelMouseEvent &evt, AudacityProject *pProject)
150{
151 auto &tracks = TrackList::Get( *pProject );
152 auto theChannel = FindChannel();
153 if (!theChannel)
155
156 auto &view = ChannelView::Get(*theChannel);
157
158 if (view.GetMinimized() && mMode == IsResizingBetweenLinkedTracks)
160
161 const wxMouseEvent &event = evt.event;
162
163 int delta = (event.m_y - mMouseClickY);
164
165 // On first drag, jump out of minimized mode. Initial height
166 // will be height of minimized track.
167 //
168 // This used to be in HandleResizeClick(), but simply clicking
169 // on a resize border would switch the minimized state.
170 if (view.GetMinimized()) {
171 auto channels = GetTrack(*theChannel).Channels();
172 for (auto pChannel : channels) {
173 auto &channelView = ChannelView::Get(*pChannel);
174 channelView.SetExpandedHeight(channelView.GetHeight());
175 channelView.SetMinimized(false);
176 }
177
178 if (channels.size() > 1) {
179 // Initial values must be reset since they weren't based on the
180 // minimized heights.
181 auto &channelView = ChannelView::Get(**channels.begin());
182 mInitialUpperTrackHeight = channelView.GetHeight();
183 mInitialTrackHeight = channelView.GetHeight();
184 }
185 }
186
187 // Common pieces of code for MONO_WAVE_PAN and otherwise.
188 auto doResizeBelow = [&] (Channel *prev) {
189 // TODO: more-than-two-channels
190
191 auto &prevView = ChannelView::Get(*prev);
192
193 double proportion = static_cast < double >(mInitialTrackHeight)
195
196 int newTrackHeight = static_cast < int >
197 (mInitialTrackHeight + delta * proportion);
198
199 int newUpperTrackHeight = static_cast < int >
200 (mInitialUpperTrackHeight + delta * (1.0 - proportion));
201
202 //make sure neither track is smaller than its minimum height
203 if (newTrackHeight < view.GetMinimizedHeight())
204 newTrackHeight = view.GetMinimizedHeight();
205 if (newUpperTrackHeight < prevView.GetMinimizedHeight())
206 newUpperTrackHeight = prevView.GetMinimizedHeight();
207
208 view.SetExpandedHeight(newTrackHeight);
209 prevView.SetExpandedHeight(newUpperTrackHeight);
210 };
211
212 auto doResizeBetween = [&] (Channel *next) {
213 // TODO: more-than-two-channels
214
215 auto &nextView = ChannelView::Get(*next);
216 int newUpperTrackHeight = mInitialUpperTrackHeight + delta;
217 int newTrackHeight = mInitialTrackHeight - delta;
218
219 // make sure neither track is smaller than its minimum height
220 if (newTrackHeight < nextView.GetMinimizedHeight()) {
221 newTrackHeight = nextView.GetMinimizedHeight();
222 newUpperTrackHeight =
223 mInitialUpperTrackHeight + mInitialTrackHeight - nextView.GetMinimizedHeight();
224 }
225 if (newUpperTrackHeight < view.GetMinimizedHeight()) {
226 newUpperTrackHeight = view.GetMinimizedHeight();
227 newTrackHeight =
228 mInitialUpperTrackHeight + mInitialTrackHeight - view.GetMinimizedHeight();
229 }
230
231 view.SetExpandedHeight(newUpperTrackHeight);
232 nextView.SetExpandedHeight(newTrackHeight);
233 };
234
235 auto doResize = [&] {
236 int newTrackHeight = mInitialTrackHeight + delta;
237 if (newTrackHeight < view.GetMinimizedHeight())
238 newTrackHeight = view.GetMinimizedHeight();
239 view.SetExpandedHeight(newTrackHeight);
240 };
241
242 //STM: We may be dragging one or two (stereo) tracks.
243 // If two, resize proportionally if we are dragging the lower track, and
244 // adjust compensatively if we are dragging the upper track.
245
246 switch( mMode )
247 {
249 {
250 // Assume previous channel is present, see constructor
251 doResizeBelow(PrevChannel(*theChannel));
252 break;
253 }
255 {
256 // Assume next channel is present, see constructor
257 doResizeBetween(NextChannel(*theChannel));
258 break;
259 }
260 case IsResizing:
261 {
262 doResize();
263 break;
264 }
265 default:
266 // don't refresh in this case.
268 }
269
271}
272
275{
277}
278
280(const TrackPanelMouseEvent &, AudacityProject *pProject,
281 wxWindow *)
282{
289 ProjectHistory::Get( *pProject ).ModifyState(false);
291}
292
294{
295 auto &tracks = TrackList::Get( *pProject );
296 auto theChannel = FindChannel();
297 if (!theChannel)
299
300
301 switch (mMode) {
302 case IsResizing:
303 {
304 auto &view = ChannelView::Get(*theChannel);
305 view.SetExpandedHeight(mInitialExpandedHeight);
306 view.SetMinimized( mInitialMinimized );
307 }
308 break;
310 {
311 // Assume next channel is present, see constructor
312 const auto next = NextChannel(*theChannel);
313 auto &view = ChannelView::Get(*theChannel),
314 &nextView = ChannelView::Get(*next);
315 view.SetExpandedHeight(mInitialUpperExpandedHeight);
316 view.SetMinimized( mInitialMinimized );
317 nextView.SetExpandedHeight(mInitialExpandedHeight);
318 nextView.SetMinimized( mInitialMinimized );
319 }
320 break;
322 {
323 // Assume previous channel is present, see constructor
324 const auto prev = PrevChannel(*theChannel);
325 auto &view = ChannelView::Get(*theChannel),
326 &prevView = ChannelView::Get(*prev);
327 view.SetExpandedHeight(mInitialExpandedHeight);
328 view.SetMinimized( mInitialMinimized );
329 prevView.SetExpandedHeight(mInitialUpperExpandedHeight);
330 prevView.SetMinimized(mInitialMinimized);
331 }
332 break;
333 }
334
336}
337
339{
340 return *static_cast<Track*>(&channel.GetChannelGroup());
341}
XO("Cut/Copy/Paste")
const auto tracks
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
IteratorRange< ChannelIterator< ChannelType > > Channels()
Get range of channels with mutative access.
Definition: Channel.h:384
ChannelGroup & GetChannelGroup()
Channel object's lifetime is assumed to be nested in its Track's.
Definition: Channel.cpp:43
static ChannelView & Get(Channel &channel)
int GetHeight() const
void SetExpandedHeight(int height)
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:110
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:314
Result Click(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
std::weak_ptr< Channel > mwChannel
HitTestPreview Preview(const TrackPanelMouseState &state, AudacityProject *pProject) override
Channel * PrevChannel(Channel &channel)
TrackPanelResizeHandle(const TrackPanelResizeHandle &)=delete
static HitTestPreview HitPreview(bool bLinked)
std::shared_ptr< Channel > FindChannel()
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) override
std::shared_ptr< const Track > FindTrack() const override
Result Cancel(AudacityProject *pProject) override
Result Release(const TrackPanelMouseEvent &event, AudacityProject *pProject, wxWindow *pParent) override
static Track & GetTrack(Channel &channel)
Channel * NextChannel(Channel &channel)
static std::shared_ptr< const Track > TrackFromChannel(const std::shared_ptr< const Channel > &pChannel)
A frequent convenience in the definition of UIHandles.
Definition: UIHandle.cpp:63
unsigned Result
Definition: UIHandle.h:40
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16