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