forked from Sneeds-Feed-and-Seed/sneedacity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTrackPanelResizeHandle.cpp
300 lines (254 loc) · 9.37 KB
/
TrackPanelResizeHandle.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/**********************************************************************
Sneedacity: A Digital Audio Editor
TrackPanelResizeHandle.cpp
Paul Licameli split from TrackPanel.cpp
**********************************************************************/
#include "TrackPanelResizeHandle.h"
#include <wx/cursor.h>
#include <wx/translation.h>
#include "HitTestResult.h"
#include "ProjectHistory.h"
#include "RefreshCode.h"
#include "Track.h"
#include "TrackPanelMouseEvent.h"
#include "tracks/ui/TrackView.h"
HitTestPreview TrackPanelResizeHandle::HitPreview(bool bLinked)
{
// TODO: more-than-two-channels-message
static wxCursor resizeCursor{ wxCURSOR_SIZENS };
/// When in the resize area we can adjust size or relative size.
// Check to see whether it is the first channel of a stereo track
if (bLinked) {
// If we are in the label we got here 'by mistake' and we're
// not actually in the resize area at all. (The resize area
// is shorter when it is between stereo tracks).
return {
XO(
"Click and drag to adjust relative size of stereo tracks, double-click to make heights equal"),
&resizeCursor
};
}
else {
return {
XO("Click and drag to resize the track."),
&resizeCursor
};
}
}
TrackPanelResizeHandle::~TrackPanelResizeHandle()
{
}
UIHandle::Result TrackPanelResizeHandle::Click(
const TrackPanelMouseEvent &evt, SneedacityProject *pProject )
{
using namespace RefreshCode;
if ( evt.event.LeftDClick() && mMode == IsResizingBetweenLinkedTracks ) {
auto &tracks = TrackList::Get( *pProject );
auto pTrack = tracks.Lock(mpTrack);
if (pTrack &&
!TrackView::Get(*pTrack).GetMinimized()) {
auto range = TrackList::Channels( pTrack.get() );
auto size = range.size();
auto height = range.sum( [](const Track *pTrack){
return TrackView::Get(*pTrack).GetHeight(); } );
int ii = 1;
int coord = 0;
for ( const auto channel : range ) {
int newCoord = ((double)ii++ /size) * height;
TrackView::Get(*channel).SetHeight( newCoord - coord );
coord = newCoord;
}
ProjectHistory::Get( *pProject ).ModifyState(false);
// Do not start a drag
return Cancelled | RefreshAll;
}
}
return RefreshNone;
}
TrackPanelResizeHandle::TrackPanelResizeHandle
( const std::shared_ptr<Track> &track, int y )
: mpTrack{ track }
, mMouseClickY( y )
{
// TODO: more-than-two-channels
//STM: Determine whether we should rescale one or two tracks
auto channels = TrackList::Channels(track.get());
auto last = *channels.rbegin();
auto &lastView = TrackView::Get( *last );
mInitialTrackHeight = lastView.GetHeight();
mInitialActualHeight = lastView.GetActualHeight();
mInitialMinimized = lastView.GetMinimized();
if (channels.size() > 1) {
auto first = *channels.begin();
auto &firstView = TrackView::Get( *first );
mInitialUpperTrackHeight = firstView.GetHeight();
mInitialUpperActualHeight = firstView.GetActualHeight();
if (track.get() == *channels.rbegin())
// capturedTrack is the lowest track
mMode = IsResizingBelowLinkedTracks;
else
// capturedTrack is not the lowest track
mMode = IsResizingBetweenLinkedTracks;
}
else
mMode = IsResizing;
}
UIHandle::Result TrackPanelResizeHandle::Drag
(const TrackPanelMouseEvent &evt, SneedacityProject *pProject)
{
auto &tracks = TrackList::Get( *pProject );
auto pTrack = tracks.Lock(mpTrack);
if ( !pTrack )
return RefreshCode::Cancelled;
auto &view = TrackView::Get( *pTrack );
const wxMouseEvent &event = evt.event;
int delta = (event.m_y - mMouseClickY);
// On first drag, jump out of minimized mode. Initial height
// will be height of minimized track.
//
// This used to be in HandleResizeClick(), but simply clicking
// on a resize border would switch the minimized state.
auto &data = TrackView::Get( *pTrack );
if (data.GetMinimized()) {
auto channels = TrackList::Channels( pTrack.get() );
for (auto channel : channels) {
auto &channelView = TrackView::Get( *channel );
channelView.SetHeight(channelView.GetHeight());
channelView.SetMinimized( false );
}
if (channels.size() > 1) {
// Initial values must be reset since they weren't based on the
// minimized heights.
auto &channelView = TrackView::Get( **channels.begin() );
mInitialUpperTrackHeight = channelView.GetHeight();
mInitialTrackHeight = channelView.GetHeight();
}
}
// Common pieces of code for MONO_WAVE_PAN and otherwise.
auto doResizeBelow = [&] (Track *prev, bool WXUNUSED(vStereo)) {
// TODO: more-than-two-channels
auto &prevView = TrackView::Get( *prev );
double proportion = static_cast < double >(mInitialTrackHeight)
/ (mInitialTrackHeight + mInitialUpperTrackHeight);
int newTrackHeight = static_cast < int >
(mInitialTrackHeight + delta * proportion);
int newUpperTrackHeight = static_cast < int >
(mInitialUpperTrackHeight + delta * (1.0 - proportion));
//make sure neither track is smaller than its minimum height
if (newTrackHeight < view.GetMinimizedHeight())
newTrackHeight = view.GetMinimizedHeight();
if (newUpperTrackHeight < prevView.GetMinimizedHeight())
newUpperTrackHeight = prevView.GetMinimizedHeight();
view.SetHeight(newTrackHeight);
prevView.SetHeight(newUpperTrackHeight);
};
auto doResizeBetween = [&] (Track *next, bool WXUNUSED(vStereo)) {
// TODO: more-than-two-channels
auto &nextView = TrackView::Get( *next );
int newUpperTrackHeight = mInitialUpperTrackHeight + delta;
int newTrackHeight = mInitialTrackHeight - delta;
// make sure neither track is smaller than its minimum height
if (newTrackHeight < nextView.GetMinimizedHeight()) {
newTrackHeight = nextView.GetMinimizedHeight();
newUpperTrackHeight =
mInitialUpperTrackHeight + mInitialTrackHeight - nextView.GetMinimizedHeight();
}
if (newUpperTrackHeight < view.GetMinimizedHeight()) {
newUpperTrackHeight = view.GetMinimizedHeight();
newTrackHeight =
mInitialUpperTrackHeight + mInitialTrackHeight - view.GetMinimizedHeight();
}
view.SetHeight(newUpperTrackHeight);
nextView.SetHeight(newTrackHeight);
};
auto doResize = [&] {
int newTrackHeight = mInitialTrackHeight + delta;
if (newTrackHeight < view.GetMinimizedHeight())
newTrackHeight = view.GetMinimizedHeight();
view.SetHeight(newTrackHeight);
};
//STM: We may be dragging one or two (stereo) tracks.
// If two, resize proportionally if we are dragging the lower track, and
// adjust compensatively if we are dragging the upper track.
switch( mMode )
{
case IsResizingBelowLinkedTracks:
{
auto prev = * -- tracks.Find(pTrack.get());
doResizeBelow(prev, false);
break;
}
case IsResizingBetweenLinkedTracks:
{
auto next = * ++ tracks.Find(pTrack.get());
doResizeBetween(next, false);
break;
}
case IsResizing:
{
doResize();
break;
}
default:
// don't refresh in this case.
return RefreshCode::RefreshNone;
}
return RefreshCode::RefreshAll;
}
HitTestPreview TrackPanelResizeHandle::Preview
(const TrackPanelMouseState &, SneedacityProject *)
{
return HitPreview(mMode == IsResizingBetweenLinkedTracks);
}
UIHandle::Result TrackPanelResizeHandle::Release
(const TrackPanelMouseEvent &, SneedacityProject *pProject,
wxWindow *)
{
/// This happens when the button is released from a drag.
/// Since we actually took care of resizing the track when
/// we got drag events, all we have to do here is clean up.
/// We also modify the undo state (the action doesn't become
/// undo-able, but it gets merged with the previous undo-able
/// event).
ProjectHistory::Get( *pProject ).ModifyState(false);
return RefreshCode::FixScrollbars;
}
UIHandle::Result TrackPanelResizeHandle::Cancel(SneedacityProject *pProject)
{
auto &tracks = TrackList::Get( *pProject );
auto pTrack = tracks.Lock(mpTrack);
if ( !pTrack )
return RefreshCode::Cancelled;
switch (mMode) {
case IsResizing:
{
auto &view = TrackView::Get( *pTrack );
view.SetHeight(mInitialActualHeight);
view.SetMinimized( mInitialMinimized );
}
break;
case IsResizingBetweenLinkedTracks:
{
Track *const next = * ++ tracks.Find(pTrack.get());
auto
&view = TrackView::Get( *pTrack ), &nextView = TrackView::Get( *next );
view.SetHeight(mInitialUpperActualHeight);
view.SetMinimized( mInitialMinimized );
nextView.SetHeight(mInitialActualHeight);
nextView.SetMinimized( mInitialMinimized );
}
break;
case IsResizingBelowLinkedTracks:
{
Track *const prev = * -- tracks.Find(pTrack.get());
auto
&view = TrackView::Get( *pTrack ), &prevView = TrackView::Get( *prev );
view.SetHeight(mInitialActualHeight);
view.SetMinimized( mInitialMinimized );
prevView.SetHeight(mInitialUpperActualHeight);
prevView.SetMinimized(mInitialMinimized);
}
break;
}
return RefreshCode::RefreshAll;
}