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 Channel> TrackPanelResizeHandle::FindChannel() const
57{
58 return 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 const wxMouseEvent &event = evt.event;
159
160 int delta = (event.m_y - mMouseClickY);
161
162 // On first drag, jump out of minimized mode. Initial height
163 // will be height of minimized track.
164 //
165 // This used to be in HandleResizeClick(), but simply clicking
166 // on a resize border would switch the minimized state.
167 if (view.GetMinimized()) {
168 auto channels = GetTrack(*theChannel).Channels();
169 for (auto pChannel : channels) {
170 auto &channelView = ChannelView::Get(*pChannel);
171 channelView.SetExpandedHeight(channelView.GetHeight());
172 channelView.SetMinimized(false);
173 }
174
175 if (channels.size() > 1) {
176 // Initial values must be reset since they weren't based on the
177 // minimized heights.
178 auto &channelView = ChannelView::Get(**channels.begin());
179 mInitialUpperTrackHeight = channelView.GetHeight();
180 mInitialTrackHeight = channelView.GetHeight();
181 }
182 }
183
184 // Common pieces of code for MONO_WAVE_PAN and otherwise.
185 auto doResizeBelow = [&] (Channel *prev) {
186 // TODO: more-than-two-channels
187
188 auto &prevView = ChannelView::Get(*prev);
189
190 double proportion = static_cast < double >(mInitialTrackHeight)
192
193 int newTrackHeight = static_cast < int >
194 (mInitialTrackHeight + delta * proportion);
195
196 int newUpperTrackHeight = static_cast < int >
197 (mInitialUpperTrackHeight + delta * (1.0 - proportion));
198
199 //make sure neither track is smaller than its minimum height
200 if (newTrackHeight < view.GetMinimizedHeight())
201 newTrackHeight = view.GetMinimizedHeight();
202 if (newUpperTrackHeight < prevView.GetMinimizedHeight())
203 newUpperTrackHeight = prevView.GetMinimizedHeight();
204
205 view.SetExpandedHeight(newTrackHeight);
206 prevView.SetExpandedHeight(newUpperTrackHeight);
207 };
208
209 auto doResizeBetween = [&] (Channel *next) {
210 // TODO: more-than-two-channels
211
212 auto &nextView = ChannelView::Get(*next);
213 int newUpperTrackHeight = mInitialUpperTrackHeight + delta;
214 int newTrackHeight = mInitialTrackHeight - delta;
215
216 // make sure neither track is smaller than its minimum height
217 if (newTrackHeight < nextView.GetMinimizedHeight()) {
218 newTrackHeight = nextView.GetMinimizedHeight();
219 newUpperTrackHeight =
220 mInitialUpperTrackHeight + mInitialTrackHeight - nextView.GetMinimizedHeight();
221 }
222 if (newUpperTrackHeight < view.GetMinimizedHeight()) {
223 newUpperTrackHeight = view.GetMinimizedHeight();
224 newTrackHeight =
225 mInitialUpperTrackHeight + mInitialTrackHeight - view.GetMinimizedHeight();
226 }
227
228 view.SetExpandedHeight(newUpperTrackHeight);
229 nextView.SetExpandedHeight(newTrackHeight);
230 };
231
232 auto doResize = [&] {
233 int newTrackHeight = mInitialTrackHeight + delta;
234 if (newTrackHeight < view.GetMinimizedHeight())
235 newTrackHeight = view.GetMinimizedHeight();
236 view.SetExpandedHeight(newTrackHeight);
237 };
238
239 //STM: We may be dragging one or two (stereo) tracks.
240 // If two, resize proportionally if we are dragging the lower track, and
241 // adjust compensatively if we are dragging the upper track.
242
243 switch( mMode )
244 {
246 {
247 // Assume previous channel is present, see constructor
248 doResizeBelow(PrevChannel(*theChannel));
249 break;
250 }
252 {
253 // Assume next channel is present, see constructor
254 doResizeBetween(NextChannel(*theChannel));
255 break;
256 }
257 case IsResizing:
258 {
259 doResize();
260 break;
261 }
262 default:
263 // don't refresh in this case.
265 }
266
268}
269
272{
274}
275
277(const TrackPanelMouseEvent &, AudacityProject *pProject,
278 wxWindow *)
279{
286 ProjectHistory::Get( *pProject ).ModifyState(false);
288}
289
291{
292 auto &tracks = TrackList::Get( *pProject );
293 auto theChannel = FindChannel();
294 if (!theChannel)
296
297
298 switch (mMode) {
299 case IsResizing:
300 {
301 auto &view = ChannelView::Get(*theChannel);
302 view.SetExpandedHeight(mInitialExpandedHeight);
303 view.SetMinimized( mInitialMinimized );
304 }
305 break;
307 {
308 // Assume next channel is present, see constructor
309 const auto next = NextChannel(*theChannel);
310 auto &view = ChannelView::Get(*theChannel),
311 &nextView = ChannelView::Get(*next);
312 view.SetExpandedHeight(mInitialUpperExpandedHeight);
313 view.SetMinimized( mInitialMinimized );
314 nextView.SetExpandedHeight(mInitialExpandedHeight);
315 nextView.SetMinimized( mInitialMinimized );
316 }
317 break;
319 {
320 // Assume previous channel is present, see constructor
321 const auto prev = PrevChannel(*theChannel);
322 auto &view = ChannelView::Get(*theChannel),
323 &prevView = ChannelView::Get(*prev);
324 view.SetExpandedHeight(mInitialExpandedHeight);
325 view.SetMinimized( mInitialMinimized );
326 prevView.SetExpandedHeight(mInitialUpperExpandedHeight);
327 prevView.SetMinimized(mInitialMinimized);
328 }
329 break;
330 }
331
333}
334
336{
337 // TODO wide wave tracks -- just return channel.GetTrack()
338 // But until then, Track::Channels() will not iterate all channels when
339 // given a right hand track
340 // So be sure to substitute the leader
341 const auto pTrack = static_cast<Track*>(&channel.GetChannelGroup());
342 return **TrackList::Channels(pTrack).begin();
343}
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:408
ChannelGroup & GetChannelGroup()
Channel object's lifetime is assumed to be nested in its Track's.
Definition: Channel.cpp:71
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:122
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:347
static auto Channels(TrackType *pTrack) -> TrackIterRange< TrackType >
Definition: Track.h:1164
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< const Channel > FindChannel() const override
Result Drag(const TrackPanelMouseEvent &event, AudacityProject *pProject) 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)
unsigned Result
Definition: UIHandle.h:39
Namespace containing an enum 'what to do on a refresh?'.
Definition: RefreshCode.h:16