Audacity 3.2.0
Viewport.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3Audacity: A Digital Audio Editor
4
5Viewport.cpp
6
7Paul Licameli split from ProjectWindow.cpp
8
9**********************************************************************/
10#include "Viewport.h"
11
12#include "BasicUI.h"
13#include "PendingTracks.h"
14#include "PlayableTrack.h" // just for AudioTrack
15#include "Project.h"
16#include "ProjectSnap.h"
17#include "TrackFocus.h"
18#include "UndoManager.h"
19#include "ViewInfo.h"
20
21#include <numeric>
22
24
28 auto result = std::make_shared<Viewport>(project);
29 return result;
30 }
31};
32
34{
35 return project.AttachedObjects::Get<Viewport>(sKey);
36}
37
39{
40 return Get(const_cast<AudacityProject &>(project));
41}
42
44 : mProject{ project }
45 , mSnappingChangedSubscription{
46 ProjectSnap::Get(project).Subscribe([this](auto&){ Redraw(); }) }
47 , mUndoSubscription{
49 switch (message.type) {
50 case UndoRedoMessage::Pushed:
51 case UndoRedoMessage::Modified:
52 return OnUndoPushedModified();
53 case UndoRedoMessage::UndoOrRedo:
54 return OnUndoRedo();
55 case UndoRedoMessage::Reset:
56 return OnUndoReset();
57 default:
58 return;
59 }
60 }) }
61{
62}
63
64void Viewport::SetCallbacks(std::unique_ptr<ViewportCallbacks> pCallbacks)
65{
66 mpCallbacks = move(pCallbacks);
67}
68
70{
71 // Set a flag so we don't have to generate two update events
72 mAutoScrolling = true;
73
74 // Call our Scroll method which updates our ViewInfo variables
75 // to reflect the positions of the scrollbars
76 DoScroll();
77
78 mAutoScrolling = false;
79}
80
81const int sbarHjump = 30; //STM: This is how far the thumb jumps when the l/r buttons are pressed, or auto-scrolling occurs -- in pixels
82
83// Make sure selection edge is in view
85{
86 auto &project = mProject;
87 auto &viewInfo = ViewInfo::Get( project );
88 auto w = viewInfo.GetTracksUsableWidth();
89
90 int pixel = viewInfo.TimeToPosition(pos);
91 if (pixel < 0 || pixel >= w) {
92 SetHorizontalThumb(viewInfo.OffsetTimeByPixels(pos, -(w / 2)));
93 Publish({ true, false, false });
94 }
95}
96
98{
99 auto &project = mProject;
100 auto &viewInfo = ViewInfo::Get( project );
101 ScrollIntoView(viewInfo.PositionToTime(x, viewInfo.GetLeftOffset()));
102}
103
105{
106 auto &project = mProject;
107 wxInt64 pos = mpCallbacks ? mpCallbacks->GetHorizontalThumbPosition() : 0;
108 const auto prevPos = pos;
109 // move at least one scroll increment
110 pos -= std::max<wxInt64>((sbarHjump * sbarScale), 1);
111 pos = std::max<wxInt64>(pos, 0);
112 sbarH -= sbarHjump;
113 sbarH = std::max<wxInt64>(sbarH, -PixelWidthBeforeTime(0.0));
114
115 if (mpCallbacks && pos != prevPos) {
116 mpCallbacks->SetHorizontalThumbPosition(static_cast<int>(pos));
118 }
119}
120
122{
123 auto &project = mProject;
124 wxInt64 pos = mpCallbacks ? mpCallbacks->GetHorizontalThumbPosition() : 0;
125 const auto prevPos = pos;
126 // move at least one scroll increment
127 // use wxInt64 for calculation to prevent temporary overflow
128 pos += std::max<wxInt64>((sbarHjump * sbarScale), 1);
129 wxInt64 max = mpCallbacks
130 ? mpCallbacks->GetHorizontalRange()
131 - mpCallbacks->GetHorizontalThumbSize()
132 : 0;
133 pos = std::min(pos, max);
134 sbarH += sbarHjump;
135 sbarH = std::min<wxInt64>(sbarH,
137
138 if (mpCallbacks && pos != prevPos) {
139 mpCallbacks->SetHorizontalThumbPosition(static_cast<int>(pos));
141 }
142}
143
145{
146 auto &project = mProject;
147 wxInt64 pos = mpCallbacks ? mpCallbacks->GetHorizontalThumbPosition() : 0;
148 const auto prevPos = pos;
149 // move at least one scroll increment
150 pos -= std::max<wxInt64>((sbarHjump * sbarScale), 1);
151 pos = std::max<wxInt64>(pos, 0);
152 sbarH -= sbarHjump;
153 sbarH = std::max<wxInt64>(sbarH, -PixelWidthBeforeTime(0.0));
154
155 if (mpCallbacks && pos != prevPos) {
156 mpCallbacks->SetHorizontalThumbPosition(static_cast<int>(pos));
157 DoScroll();
158 }
159}
160
162{
163 auto &project = mProject;
164 wxInt64 pos = mpCallbacks ? mpCallbacks->GetHorizontalThumbPosition() : 0;
165 const auto prevPos = pos;
166 // move at least one scroll increment
167 // use wxInt64 for calculation to prevent temporary overflow
168 pos += std::max<wxInt64>((sbarHjump * sbarScale), 1);
169 wxInt64 max = mpCallbacks
170 ? mpCallbacks->GetHorizontalRange()
171 - mpCallbacks->GetHorizontalThumbSize()
172 : 0;
173 pos = std::min(pos, max);
174 sbarH += sbarHjump;
175 sbarH = std::min<wxInt64>(sbarH,
177
178 if (mpCallbacks && pos != prevPos) {
179 mpCallbacks->SetHorizontalThumbPosition(static_cast<int>(pos));
180 DoScroll();
181 }
182}
183
185{
186 return 0;
187}
188
189// PRL: Bug1197: we seem to need to compute all in double, to avoid differing results on Mac
190// That's why ViewInfo::TimeRangeToPixelWidth was defined, with some regret.
191double Viewport::PixelWidthBeforeTime(double scrollto) const
192{
193 auto &project = mProject;
194 auto &viewInfo = ViewInfo::Get( project );
195 const double lowerBound = ScrollingLowerBoundTime();
196 return
197 // Ignoring fisheye is correct here
198 viewInfo.TimeRangeToPixelWidth(scrollto - lowerBound);
199}
200
201void Viewport::SetHorizontalThumb(double scrollto, bool doScroll)
202{
203 if (!mpCallbacks)
204 return;
205 auto &project = mProject;
206 const auto unscaled = PixelWidthBeforeTime(scrollto);
207 const int max = std::max(
208 0, mpCallbacks->GetHorizontalRange() -
209 mpCallbacks->GetHorizontalThumbSize());
210 const int pos = std::clamp<int>(floor(0.5 + unscaled * sbarScale), 0, max);
211 mpCallbacks->SetHorizontalThumbPosition(pos);
212 sbarH = floor(0.5 + unscaled - PixelWidthBeforeTime(0.0));
213 sbarH = std::clamp<wxInt64>(
215 std::max(sbarTotal - PixelWidthBeforeTime(0.0) - sbarScreen, 0.));
216
217 if (doScroll)
218 DoScroll();
219}
220
222{
223 int oldPos = mpCallbacks ? mpCallbacks->GetVerticalThumbPosition() : 0;
224 int pos = oldPos + delta;
225 int max = mpCallbacks
226 ? mpCallbacks->GetVerticalRange() - mpCallbacks->GetVerticalThumbSize()
227 : 0;
228
229 // Can be negative in case of only one track
230 if (max < 0)
231 max = 0;
232
233 if (pos > max)
234 pos = max;
235 else if (pos < 0)
236 pos = 0;
237
238 if (pos != oldPos)
239 {
240 if (mpCallbacks)
241 mpCallbacks->SetVerticalThumbPosition(pos);
242
243 DoScroll();
244 return true;
245 }
246 else
247 return false;
248}
249
251{
252 auto &project = mProject;
253 auto &tracks = TrackList::Get( project );
254 auto &viewInfo = ViewInfo::Get( project );
255
256 // To decide whether to repaint the view
257 bool refresh = false;
258 bool rescroll = false;
259
260 // Gather inputs
261 const int totalHeight =
262 (mpCallbacks ? mpCallbacks->GetTotalHeight(tracks) : 0) + 32;
263
264 // (From Debian...at least I think this is the change corresponding
265 // to this comment)
266 //
267 // (2.) GTK critical warning "IA__gtk_range_set_range: assertion
268 // 'min < max' failed" because of negative numbers as result of window
269 // size checking. Added a sanity check that straightens up the numbers
270 // in edge cases.
271 const auto panelWidth = std::max(0, viewInfo.GetTracksUsableWidth());
272 const auto panelHeight = std::max(0, viewInfo.GetHeight());
273
274 // Whether scrollbars are visible now
275 const bool oldhstate = (viewInfo.GetScreenEndTime() - viewInfo.hpos) < total;
276 const bool oldvstate = panelHeight < totalHeight;
277
278 auto &pendingTracks = PendingTracks::Get(mProject);
279 const auto LastTime = std::accumulate(tracks.begin(), tracks.end(),
280 viewInfo.selectedRegion.t1(),
281 [&pendingTracks](double acc, const Track *track){
282 // Iterate over pending changed tracks if present.
283 track = &pendingTracks.SubstitutePendingChangedTrack(*track);
284 return std::max(acc, track->GetEndTime());
285 });
286
287 const double screen = viewInfo.GetScreenEndTime() - viewInfo.hpos;
288 const double halfScreen = screen / 2.0;
289
290 const double lowerBound = ScrollingLowerBoundTime();
291 const double additional = screen / 4.0;
292
293 total = LastTime + additional;
294
295 // Don't remove time from total that's still on the screen
296 total = std::max(total, viewInfo.hpos + screen);
297
298 // Scroll the view later if needed to respect the lower bound
299 if (viewInfo.hpos < lowerBound) {
300 viewInfo.hpos = lowerBound;
301 rescroll = true;
302 }
303
304 // To compute new horizontal scrollbar settings
305 sbarTotal = static_cast<wxInt64>(total * viewInfo.GetZoom());
306 sbarScreen = static_cast<wxInt64>(panelWidth);
307 sbarH = static_cast<wxInt64>(viewInfo.GetBeforeScreenWidth());
308
309 // PRL: Can someone else find a more elegant solution to bug 812, than
310 // introducing this boolean member variable?
311 // Setting mVSbar earlier, in HandlXMLTag, didn't succeed in restoring
312 // the vertical scrollbar to its saved position. So defer that till now.
313 // mbInitializingScrollbar should be true only at the start of the life
314 // of an AudacityProject reopened from disk.
316 viewInfo.vpos =
317 (mpCallbacks ? mpCallbacks->GetVerticalThumbPosition() : 0)
318 * scrollStep;
320
321 // Constrain new top of visible area
322 viewInfo.vpos = std::clamp(viewInfo.vpos, 0, totalHeight - 1);
323
324 // Decide whether the tracks are large enough to scroll for the zoom level
325 // and heights
326 bool newhstate =
327 (viewInfo.GetScreenEndTime() - viewInfo.hpos) < total;
328 bool newvstate = panelHeight < totalHeight;
329
330 // Hide scrollbar thumbs and buttons if not scrollable
331 if (mpCallbacks) {
332 mpCallbacks->ShowHorizontalScrollbar(newhstate);
333 mpCallbacks->ShowVerticalScrollbar(newvstate);
334 }
335
336 // When not scrollable in either axis, align viewport to top or left and
337 // repaint it later
338 if (!newvstate && viewInfo.vpos != 0) {
339 viewInfo.vpos = 0;
340
341 refresh = true;
342 rescroll = false;
343 }
344 if (!newhstate && sbarH != 0) {
345 sbarH = 0;
346
347 refresh = true;
348 rescroll = false;
349 }
350
351 // wxScrollbar only supports int values but we need a greater range, so
352 // we scale the scrollbar coordinates on demand. We only do this if we
353 // would exceed the int range, so we can always use the maximum resolution
354 // available.
355
356 // Don't use the full 2^31 max int range but a bit less, so rounding
357 // errors in calculations do not overflow max int
358 wxInt64 maxScrollbarRange = (wxInt64)(2147483647 * 0.999);
359 if (sbarTotal > maxScrollbarRange)
360 sbarScale = (static_cast<double>(maxScrollbarRange)) / sbarTotal;
361 else
362 sbarScale = 1.0; // use maximum resolution
363
364 {
365 auto scaledSbarH = static_cast<int>(sbarH * sbarScale);
366 auto scaledSbarScreen = static_cast<int>(sbarScreen * sbarScale);
367 auto scaledSbarTotal = static_cast<int>(sbarTotal * sbarScale);
368 const auto offset =
369 static_cast<int>(floor(0.5 + sbarScale * PixelWidthBeforeTime(0.0)));
370
371 if (mpCallbacks)
372 mpCallbacks->SetHorizontalScrollbar(
373 scaledSbarH + offset, scaledSbarScreen, scaledSbarTotal,
374 scaledSbarScreen, true);
375 }
376
377 if (mpCallbacks)
378 mpCallbacks->SetVerticalScrollbar(viewInfo.vpos / scrollStep,
379 panelHeight / scrollStep,
380 totalHeight / scrollStep,
381 panelHeight / scrollStep, true);
382
383 rescroll = (rescroll &&
384 (viewInfo.GetScreenEndTime() - viewInfo.hpos) < total);
385 Publish({ (refresh || rescroll),
386 (oldhstate != newhstate || oldvstate != newvstate), false });
387}
388
390{
391 BasicUI::CallAfter( [wthis = weak_from_this()]{
392 if (auto This = wthis.lock()) {
393 This->UpdateScrollbarsForTracks();
394 This->Publish({ false, false, true });
395 }
396 });
397}
398
400{
401 auto &project = mProject;
402 auto &viewInfo = ViewInfo::Get( project );
403 const wxInt64 offset = PixelWidthBeforeTime(0.0);
404 const auto pos = mpCallbacks ? mpCallbacks->GetHorizontalThumbPosition() : 0;
405 sbarH = static_cast<wxInt64>(pos / sbarScale) - offset;
406 DoScroll();
407
408#ifndef __WXMAC__
409 // Bug2179
410 // This keeps the time ruler in sync with horizontal scrolling, without
411 // making an undesirable compilation dependency of this source file on
412 // the ruler
414#endif
415}
416
418{
419 auto &project = mProject;
420 auto &viewInfo = ViewInfo::Get( project );
421 const double lowerBound = ScrollingLowerBoundTime();
422
423 auto width = viewInfo.GetTracksUsableWidth();
424 const auto zoom = viewInfo.GetZoom();
425 viewInfo.hpos = std::clamp(sbarH / zoom, lowerBound, std::max(lowerBound, total - width / zoom));
426
427 const auto pos = mpCallbacks ? mpCallbacks->GetVerticalThumbPosition() : 0;
428 viewInfo.vpos = pos * scrollStep;
429
430 //mchinen: do not always set this project to be the active one.
431 //a project may autoscroll while playing in the background
432 //I think this is okay since OnMouseEvent has one of these.
433 //SetActiveProject(this);
434
435 if (!mAutoScrolling)
436 Publish({ true, false, false });
437}
438
440{
441 auto &project = mProject;
442 auto &tracks = TrackList::Get( project );
443
445
446 if (!pTrack)
447 pTrack = *tracks.Selected().begin();
448 if (!pTrack)
449 pTrack = *tracks.begin();
450 if (pTrack) {
451 TrackFocus::Get(project).Set(pTrack, true);
452 ShowTrack(*pTrack);
453 }
454}
455
456void Viewport::ShowTrack(const Track &track)
457{
458 auto &viewInfo = ViewInfo::Get(mProject);
459
460 int trackTop = 0;
461 int trackHeight = 0;
462 for (auto it : TrackList::Get(mProject)) {
463 trackTop += trackHeight;
464 trackHeight = mpCallbacks ? mpCallbacks->GetTrackHeight(*it) : 0;
465
466 if (it == &track) {
467 //We have found the track we want to ensure is visible.
468
469 //Get the size of the trackpanel.
470 const auto size =
471 mpCallbacks ? mpCallbacks->ViewportSize() : std::pair{ 1, 1 };
472 auto [width, height] = size;
473
474 if (trackTop < viewInfo.vpos) {
475 height = viewInfo.vpos - trackTop + scrollStep;
476 height /= scrollStep;
477 ScrollUpDown(-height);
478 }
479 else if (trackTop + trackHeight > viewInfo.vpos + height) {
480 height = (trackTop + trackHeight) - (viewInfo.vpos + height);
481 height = (height + scrollStep + 1) / scrollStep;
482 ScrollUpDown(height);
483 }
484
485 break;
486 }
487 }
488
489 Publish({ true, false, false });
490}
491
492// Utility function called by other zoom methods
493void Viewport::Zoom(double pixelsPerSecond)
494{
495 auto &project = mProject;
496 auto &viewInfo = ViewInfo::Get( project );
497 viewInfo.SetZoom(pixelsPerSecond);
499 // See if we can center the selection on screen, and have it actually fit.
500 // tOnLeft is the amount of time we would need before the selection left edge to center it.
501 float t0 = viewInfo.selectedRegion.t0();
502 float t1 = viewInfo.selectedRegion.t1();
503 float tAvailable = viewInfo.GetScreenEndTime() - viewInfo.hpos;
504 float tOnLeft = (tAvailable - t0 + t1)/2.0;
505 // Bug 1292 (Enh) is effectively a request to do this scrolling of the selection into view.
506 // If tOnLeft is positive, then we have room for the selection, so scroll to it.
507 if (tOnLeft >= 0)
508 SetHorizontalThumb(t0 - tOnLeft);
509}
510
511void Viewport::ZoomBy(double multiplier)
512{
513 auto &project = mProject;
514 auto &viewInfo = ViewInfo::Get( project );
515 viewInfo.ZoomBy(multiplier);
517}
518
519void Viewport::ScrollToStart(bool extend)
520{
521 auto &project = mProject;
522 auto &viewInfo = ViewInfo::Get( project );
523 viewInfo.selectedRegion.setT0(0, false);
524 if (!extend)
525 viewInfo.selectedRegion.setT1(0);
526
528}
529
531{
532 if (mpCallbacks)
533 mpCallbacks->SetVerticalThumbPosition(0);
534}
535
536
537void Viewport::ScrollToEnd(bool extend)
538{
539 auto &project = mProject;
541 auto &viewInfo = ViewInfo::Get(project);
542 double len = tracks.GetEndTime();
543
544 viewInfo.selectedRegion.setT1(len, false);
545 if (!extend)
546 viewInfo.selectedRegion.setT0(len);
547
548 // Make sure the end of the track is visible
549 ScrollIntoView(len);
550}
551
553{
554 auto &project = mProject;
556 auto &viewInfo = ViewInfo::Get(project);
557
558 auto range = tracks.Any();
559 int trackHeight = 0;
560 const auto getHeight = [this](auto pTrack){
561 return mpCallbacks ? mpCallbacks->GetTrackHeight(*pTrack) : 0;
562 };
563 if (!range.empty()) {
564 trackHeight = getHeight(*range.rbegin());
565 --range.second;
566 }
567 int trackTop =
568 range.sum(getHeight);
569 const auto size =
570 mpCallbacks ? mpCallbacks->ViewportSize() : std::pair{ 1, 1 };
571 const auto [width, height] = size;
572 const auto step = scrollStep;
573 const int delta = ((trackTop + trackHeight - height) - viewInfo.vpos
574 + step) / step;
575 ScrollUpDown(delta);
576 Publish({ true, false, false });
577}
578
579void Viewport::ZoomAboutSelection(double multiplier)
580{
581 auto &project = mProject;
582 auto &viewInfo = ViewInfo::Get( project );
583
584 // DMM: Here's my attempt to get logical zooming behavior
585 // when there's a selection that's currently at least
586 // partially on-screen
587
588 const double endTime = viewInfo.GetScreenEndTime();
589 const double duration = endTime - viewInfo.hpos;
590
591 bool selectionIsOnscreen =
592 (viewInfo.selectedRegion.t0() < endTime) &&
593 (viewInfo.selectedRegion.t1() >= viewInfo.hpos);
594
595 bool selectionFillsScreen =
596 (viewInfo.selectedRegion.t0() < viewInfo.hpos) &&
597 (viewInfo.selectedRegion.t1() > endTime);
598
599 if (selectionIsOnscreen && !selectionFillsScreen) {
600 // Start with the center of the selection
601 double selCenter = (viewInfo.selectedRegion.t0() +
602 viewInfo.selectedRegion.t1()) / 2;
603
604 // If the selection center is off-screen, pick the
605 // center of the part that is on-screen.
606 if (selCenter < viewInfo.hpos)
607 selCenter = viewInfo.hpos +
608 (viewInfo.selectedRegion.t1() - viewInfo.hpos) / 2;
609 if (selCenter > endTime)
610 selCenter = endTime -
611 (endTime - viewInfo.selectedRegion.t0()) / 2;
612
613 // Zoom in
614 ZoomBy(multiplier);
615 const double newDuration =
616 viewInfo.GetScreenEndTime() - viewInfo.hpos;
617
618 // Recenter on selCenter
619 SetHorizontalThumb(selCenter - newDuration / 2);
620 return;
621 }
622
623
624 double origLeft = viewInfo.hpos;
625 double origWidth = duration;
626 ZoomBy(multiplier);
627
628 const double newDuration =
629 viewInfo.GetScreenEndTime() - viewInfo.hpos;
630 double newh = origLeft + (origWidth - newDuration) / 2;
631
632 // MM: Commented this out because it was confusing users
633 /*
634 // make sure that the *right-hand* end of the selection is
635 // no further *left* than 1/3 of the way across the screen
636 if (viewInfo.selectedRegion.t1() < newh + viewInfo.screen / 3)
637 newh = viewInfo.selectedRegion.t1() - viewInfo.screen / 3;
638
639 // make sure that the *left-hand* end of the selection is
640 // no further *right* than 2/3 of the way across the screen
641 if (viewInfo.selectedRegion.t0() > newh + viewInfo.screen * 2 / 3)
642 newh = viewInfo.selectedRegion.t0() - viewInfo.screen * 2 / 3;
643 */
644
645 SetHorizontalThumb(newh);
646}
647
648void Viewport::ZoomAboutCenter(double multiplier)
649{
650 auto &project = mProject;
651 auto &viewInfo = ViewInfo::Get( project );
652
653 //Zoom() may change these, so record original values:
654 const double origLeft = viewInfo.hpos;
655 const double origWidth = viewInfo.GetScreenEndTime() - origLeft;
656
657 ZoomBy(multiplier);
658 const double newWidth = viewInfo.GetScreenEndTime() - viewInfo.hpos;
659
660 const double newh = origLeft + (origWidth - newWidth) / 2;
661 // newh = (newh > 0) ? newh : 0;
662 SetHorizontalThumb(newh);
663}
664
666{
667 auto &project = mProject;
669 auto &viewInfo = ViewInfo::Get(project);
670
671 const double end = tracks.GetEndTime();
672 const double start = 0;
673 const double len = end - start;
674
675 if (len <= 0.0)
676 return viewInfo.GetZoom();
677
678 auto w = viewInfo.GetTracksUsableWidth();
679 w -= 10;
680 return w/len;
681}
682
684{
685 auto &project = mProject;
686 auto &viewInfo = ViewInfo::Get(project);
688
689 const double start = 0;
690
692 SetHorizontalThumb(start);
693}
694
696{
697 if (!mpCallbacks)
698 return;
699 auto &project = mProject;
700 auto &viewInfo = ViewInfo::Get(project);
702
703 // Only nonminimized audio tracks will be resized
704 // Assume all channels of the track have the same minimization state
705 auto range = tracks.Any<AudioTrack>()
706 - [this](const Track *pTrack){
707 return mpCallbacks->IsTrackMinimized(*pTrack); };
708 auto count = static_cast<int>(range.sum(&Track::NChannels));
709 if (count == 0)
710 return;
711
712 // Find total height to apportion
713 auto height = viewInfo.GetHeight();
714 height -= 28;
715
716 // The height of minimized and non-audio tracks cannot be apportioned
717 const auto fn = [this](const Track *pTrack){
718 return mpCallbacks->GetTrackHeight(*pTrack);
719 };
720 height -= tracks.Any().sum(fn) - range.sum(fn);
721 height /= count;
722 height = std::max<int>(mpCallbacks->MinimumTrackHeight(), height);
723 for (auto t : range)
724 mpCallbacks->SetChannelHeights(*t, height);
725
726 ScrollToTop();
727}
728
730{
731 if (!mpCallbacks)
732 return;
733 auto &project = mProject;
735 for (auto t : tracks)
736 mpCallbacks->SetMinimized(*t, false);
737}
738
740{
741 if (!mpCallbacks)
742 return;
743 auto &project = mProject;
745 for (auto t : tracks)
746 mpCallbacks->SetMinimized(*t, true);
747}
748
750{
751 // Delay it until after channel views update their Y coordinates in response
752 // to TrackList mesages
753 BasicUI::CallAfter([wthis = weak_from_this()]{
754 if (auto This = wthis.lock()) {
755 This->UpdateScrollbarsForTracks();
756 This->Publish({ true, false, false });
757 }
758 });
759}
760
762{
763 if (mpCallbacks)
764 mpCallbacks->SetToDefaultSize();
765}
766
768{
769 Redraw();
770}
771
773{
774 HandleResize();
775 Redraw();
776}
777
779{
780 HandleResize();
781 // Redraw(); // Should we do this here too?
782}
Toolkit-neutral facade for basic user interface services.
int min(int a, int b)
Extends Track with notions of mute and solo setting.
const auto tracks
const auto project
static const AudacityProject::AttachedObjects::RegisteredFactory sKey
Definition: Viewport.cpp:26
const int sbarHjump
Definition: Viewport.cpp:81
static const auto fn
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
Track subclass holding data representing sound (as notes, or samples, or ...)
Definition: PlayableTrack.h:21
virtual size_t NChannels() const =0
Report the number of channels.
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
Definition: ClientData.h:275
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
CallbackReturn Publish(const ViewportMessage &message)
Send a message to connected callbacks.
Definition: Observer.h:207
static PendingTracks & Get(AudacityProject &project)
Project snapping settings.
Definition: ProjectSnap.h:29
Track * Get()
Definition: TrackFocus.cpp:156
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
static UndoManager & Get(AudacityProject &project)
Definition: UndoManager.cpp:71
static ViewInfo & Get(AudacityProject &project)
Definition: ViewInfo.cpp:235
virtual ~ViewportCallbacks()
void OnScrollLeft()
Definition: Viewport.cpp:104
void ZoomFitVertically()
Definition: Viewport.cpp:695
void OnScrollLeftButton()
Definition: Viewport.cpp:144
void ZoomAboutSelection(double multiplier)
Definition: Viewport.cpp:579
void ScrollToBottom()
Definition: Viewport.cpp:552
void SetCallbacks(std::unique_ptr< ViewportCallbacks > pCallbacks)
Definition: Viewport.cpp:64
void CollapseAllTracks()
Definition: Viewport.cpp:739
void OnScrollRight()
Definition: Viewport.cpp:121
wxInt64 sbarTotal
Definition: Viewport.h:203
void UpdateScrollbarsForTracks()
Definition: Viewport.cpp:250
AudacityProject & mProject
Definition: Viewport.h:190
wxInt64 sbarScreen
Definition: Viewport.h:202
std::unique_ptr< ViewportCallbacks > mpCallbacks
Definition: Viewport.h:191
void ExpandAllTracks()
Definition: Viewport.cpp:729
void Zoom(double pixelsPerSecond)
Set timeline magnification; unchanged left edge time.
Definition: Viewport.cpp:493
bool mbInitializingScrollbar
Definition: Viewport.h:215
void Redraw()
Definition: Viewport.cpp:749
Viewport(AudacityProject &project)
Definition: Viewport.cpp:43
void ShowTrack(const Track &track)
Definition: Viewport.cpp:456
void ZoomFitHorizontally()
Definition: Viewport.cpp:683
void OnScrollRightButton()
Definition: Viewport.cpp:161
void OnScroll()
Definition: Viewport.cpp:399
void ScrollToEnd(bool extend)
Definition: Viewport.cpp:537
void ScrollToTop()
Definition: Viewport.cpp:530
void SetToDefaultSize()
Send a message to the main window PARENT of the viewport, to resize.
Definition: Viewport.cpp:761
void OnUndoRedo()
Definition: Viewport.cpp:772
void ZoomBy(double multiplier)
Multiply the magnification; unchanged left edge time.
Definition: Viewport.cpp:511
int scrollStep
Definition: Viewport.h:212
double sbarScale
Definition: Viewport.h:209
void SetHorizontalThumb(double scrollto, bool doScroll=true)
Definition: Viewport.cpp:201
void ZoomFitHorizontallyAndShowTrack(Track *pTrack)
Definition: Viewport.cpp:439
void HandleResize()
Definition: Viewport.cpp:389
void ScrollToStart(bool extend)
Definition: Viewport.cpp:519
void DoScroll()
Cause refresh of viewport contents after setting scrolling or zooming.
Definition: Viewport.cpp:417
static Viewport & Get(AudacityProject &project)
Definition: Viewport.cpp:33
void ZoomAboutCenter(double multiplier)
Multiply timeline magnification, conserving the midpoint time if possible.
Definition: Viewport.cpp:648
void ScrollIntoView(double pos)
Center view horizontally at the given time, if it was not in bounds.
Definition: Viewport.cpp:84
void OnUndoPushedModified()
Definition: Viewport.cpp:767
bool ScrollUpDown(int delta)
Definition: Viewport.cpp:221
void FinishAutoScroll()
Definition: Viewport.cpp:69
bool mAutoScrolling
Definition: Viewport.h:214
double ScrollingLowerBoundTime() const
Definition: Viewport.cpp:184
wxInt64 sbarH
Definition: Viewport.h:201
double PixelWidthBeforeTime(double scrollto) const
Definition: Viewport.cpp:191
void OnUndoReset()
Definition: Viewport.cpp:778
double GetZoomOfToFit() const
Find pixels-per-second that would fit all tracks on the timeline.
Definition: Viewport.cpp:665
double total
Definition: Viewport.h:198
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:213
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:201
void Yield()
Dispatch waiting events, including actions enqueued by CallAfter.
Definition: BasicUI.cpp:224
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
Type of message published by UndoManager.
Definition: UndoManager.h:55
enum UndoRedoMessage::Type type