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 /* Leo: This has been broken forever (2.0.0/Win11)
331 and causes the bars to not show on Lin since 3.2. #2937 */
332 // Hide scrollbar thumbs and buttons if not scrollable
333 // if (mpCallbacks) {
334 // mpCallbacks->ShowHorizontalScrollbar(newhstate);
335 // mpCallbacks->ShowVerticalScrollbar(newvstate);
336 // }
337
338 // When not scrollable in either axis, align viewport to top or left and
339 // repaint it later
340 if (!newvstate && viewInfo.vpos != 0) {
341 viewInfo.vpos = 0;
342
343 refresh = true;
344 rescroll = false;
345 }
346 if (!newhstate && sbarH != 0) {
347 sbarH = 0;
348
349 refresh = true;
350 rescroll = false;
351 }
352
353 // wxScrollbar only supports int values but we need a greater range, so
354 // we scale the scrollbar coordinates on demand. We only do this if we
355 // would exceed the int range, so we can always use the maximum resolution
356 // available.
357
358 // Don't use the full 2^31 max int range but a bit less, so rounding
359 // errors in calculations do not overflow max int
360 wxInt64 maxScrollbarRange = (wxInt64)(2147483647 * 0.999);
361 if (sbarTotal > maxScrollbarRange)
362 sbarScale = (static_cast<double>(maxScrollbarRange)) / sbarTotal;
363 else
364 sbarScale = 1.0; // use maximum resolution
365
366 {
367 auto scaledSbarH = static_cast<int>(sbarH * sbarScale);
368 auto scaledSbarScreen = static_cast<int>(sbarScreen * sbarScale);
369 auto scaledSbarTotal = static_cast<int>(sbarTotal * sbarScale);
370 const auto offset =
371 static_cast<int>(floor(0.5 + sbarScale * PixelWidthBeforeTime(0.0)));
372
373 if (mpCallbacks)
374 mpCallbacks->SetHorizontalScrollbar(
375 scaledSbarH + offset, scaledSbarScreen, scaledSbarTotal,
376 scaledSbarScreen, true);
377 }
378
379 if (mpCallbacks)
380 mpCallbacks->SetVerticalScrollbar(viewInfo.vpos / scrollStep,
381 panelHeight / scrollStep,
382 totalHeight / scrollStep,
383 panelHeight / scrollStep, true);
384
385 //Leo: this needs to be rescroll = rescroll && (...
386 //if scrollbar hiding is to be reimplemented.
387 //Or maybe not. It's all broken anyway. #2937
388 rescroll = (viewInfo.GetScreenEndTime() - viewInfo.hpos) < total;
389 Publish({ (refresh || rescroll),
390 (oldhstate != newhstate || oldvstate != newvstate), false });
391}
392
394{
395 BasicUI::CallAfter( [wthis = weak_from_this()]{
396 if (auto This = wthis.lock()) {
397 This->UpdateScrollbarsForTracks();
398 This->Publish({ false, false, true });
399 }
400 });
401}
402
404{
405 auto &project = mProject;
406 auto &viewInfo = ViewInfo::Get( project );
407 const wxInt64 offset = PixelWidthBeforeTime(0.0);
408 const auto pos = mpCallbacks ? mpCallbacks->GetHorizontalThumbPosition() : 0;
409 sbarH = static_cast<wxInt64>(pos / sbarScale) - offset;
410 DoScroll();
411
412#ifndef __WXMAC__
413 // Bug2179
414 // This keeps the time ruler in sync with horizontal scrolling, without
415 // making an undesirable compilation dependency of this source file on
416 // the ruler
418#endif
419}
420
422{
423 auto &project = mProject;
424 auto &viewInfo = ViewInfo::Get( project );
425 const double lowerBound = ScrollingLowerBoundTime();
426
427 auto width = viewInfo.GetTracksUsableWidth();
428 const auto zoom = viewInfo.GetZoom();
429 viewInfo.hpos = std::clamp(sbarH / zoom, lowerBound, std::max(lowerBound, total - width / zoom));
430
431 const auto pos = mpCallbacks ? mpCallbacks->GetVerticalThumbPosition() : 0;
432 viewInfo.vpos = pos * scrollStep;
433
434 //mchinen: do not always set this project to be the active one.
435 //a project may autoscroll while playing in the background
436 //I think this is okay since OnMouseEvent has one of these.
437 //SetActiveProject(this);
438
439 if (!mAutoScrolling)
440 Publish({ true, false, false });
441}
442
444{
445 auto &project = mProject;
446 auto &tracks = TrackList::Get( project );
447
449
450 if (!pTrack)
451 pTrack = *tracks.Selected().begin();
452 if (!pTrack)
453 pTrack = *tracks.begin();
454 if (pTrack) {
455 TrackFocus::Get(project).Set(pTrack, true);
456 ShowTrack(*pTrack);
457 }
458}
459
460void Viewport::ShowTrack(const Track &track)
461{
462 auto &viewInfo = ViewInfo::Get(mProject);
463
464 int trackTop = 0;
465 int trackHeight = 0;
466 for (auto it : TrackList::Get(mProject)) {
467 trackTop += trackHeight;
468 trackHeight = mpCallbacks ? mpCallbacks->GetTrackHeight(*it) : 0;
469
470 if (it == &track) {
471 //We have found the track we want to ensure is visible.
472
473 //Get the size of the trackpanel.
474 const auto size =
475 mpCallbacks ? mpCallbacks->ViewportSize() : std::pair{ 1, 1 };
476 auto [width, height] = size;
477
478 if (trackTop < viewInfo.vpos) {
479 height = viewInfo.vpos - trackTop + scrollStep;
480 height /= scrollStep;
481 ScrollUpDown(-height);
482 }
483 else if (trackTop + trackHeight > viewInfo.vpos + height) {
484 height = (trackTop + trackHeight) - (viewInfo.vpos + height);
485 height = (height + scrollStep + 1) / scrollStep;
486 ScrollUpDown(height);
487 }
488
489 break;
490 }
491 }
492
493 Publish({ true, false, false });
494}
495
496// Utility function called by other zoom methods
497void Viewport::Zoom(double pixelsPerSecond)
498{
499 auto &project = mProject;
500 auto &viewInfo = ViewInfo::Get( project );
501 viewInfo.SetZoom(pixelsPerSecond);
503 // See if we can center the selection on screen, and have it actually fit.
504 // tOnLeft is the amount of time we would need before the selection left edge to center it.
505 float t0 = viewInfo.selectedRegion.t0();
506 float t1 = viewInfo.selectedRegion.t1();
507 float tAvailable = viewInfo.GetScreenEndTime() - viewInfo.hpos;
508 float tOnLeft = (tAvailable - t0 + t1)/2.0;
509 // Bug 1292 (Enh) is effectively a request to do this scrolling of the selection into view.
510 // If tOnLeft is positive, then we have room for the selection, so scroll to it.
511 if (tOnLeft >= 0)
512 SetHorizontalThumb(t0 - tOnLeft);
513}
514
515void Viewport::ZoomBy(double multiplier)
516{
517 auto &project = mProject;
518 auto &viewInfo = ViewInfo::Get( project );
519 viewInfo.ZoomBy(multiplier);
521}
522
523void Viewport::ScrollToStart(bool extend)
524{
525 auto &project = mProject;
526 auto &viewInfo = ViewInfo::Get( project );
527 viewInfo.selectedRegion.setT0(0, false);
528 if (!extend)
529 viewInfo.selectedRegion.setT1(0);
530
532}
533
535{
536 if (mpCallbacks)
537 mpCallbacks->SetVerticalThumbPosition(0);
538}
539
540
541void Viewport::ScrollToEnd(bool extend)
542{
543 auto &project = mProject;
545 auto &viewInfo = ViewInfo::Get(project);
546 double len = tracks.GetEndTime();
547
548 viewInfo.selectedRegion.setT1(len, false);
549 if (!extend)
550 viewInfo.selectedRegion.setT0(len);
551
552 // Make sure the end of the track is visible
553 ScrollIntoView(len);
554}
555
557{
558 auto &project = mProject;
560 auto &viewInfo = ViewInfo::Get(project);
561
562 auto range = tracks.Any();
563 int trackHeight = 0;
564 const auto getHeight = [this](auto pTrack){
565 return mpCallbacks ? mpCallbacks->GetTrackHeight(*pTrack) : 0;
566 };
567 if (!range.empty()) {
568 trackHeight = getHeight(*range.rbegin());
569 --range.second;
570 }
571 int trackTop =
572 range.sum(getHeight);
573 const auto size =
574 mpCallbacks ? mpCallbacks->ViewportSize() : std::pair{ 1, 1 };
575 const auto [width, height] = size;
576 const auto step = scrollStep;
577 const int delta = ((trackTop + trackHeight - height) - viewInfo.vpos
578 + step) / step;
579 ScrollUpDown(delta);
580 Publish({ true, false, false });
581}
582
583void Viewport::ZoomAboutSelection(double multiplier)
584{
585 auto &project = mProject;
586 auto &viewInfo = ViewInfo::Get( project );
587
588 // DMM: Here's my attempt to get logical zooming behavior
589 // when there's a selection that's currently at least
590 // partially on-screen
591
592 const double endTime = viewInfo.GetScreenEndTime();
593 const double duration = endTime - viewInfo.hpos;
594
595 bool selectionIsOnscreen =
596 (viewInfo.selectedRegion.t0() < endTime) &&
597 (viewInfo.selectedRegion.t1() >= viewInfo.hpos);
598
599 bool selectionFillsScreen =
600 (viewInfo.selectedRegion.t0() < viewInfo.hpos) &&
601 (viewInfo.selectedRegion.t1() > endTime);
602
603 if (selectionIsOnscreen && !selectionFillsScreen) {
604 // Start with the center of the selection
605 double selCenter = (viewInfo.selectedRegion.t0() +
606 viewInfo.selectedRegion.t1()) / 2;
607
608 // If the selection center is off-screen, pick the
609 // center of the part that is on-screen.
610 if (selCenter < viewInfo.hpos)
611 selCenter = viewInfo.hpos +
612 (viewInfo.selectedRegion.t1() - viewInfo.hpos) / 2;
613 if (selCenter > endTime)
614 selCenter = endTime -
615 (endTime - viewInfo.selectedRegion.t0()) / 2;
616
617 // Zoom in
618 ZoomBy(multiplier);
619 const double newDuration =
620 viewInfo.GetScreenEndTime() - viewInfo.hpos;
621
622 // Recenter on selCenter
623 SetHorizontalThumb(selCenter - newDuration / 2);
624 return;
625 }
626
627
628 double origLeft = viewInfo.hpos;
629 double origWidth = duration;
630 ZoomBy(multiplier);
631
632 const double newDuration =
633 viewInfo.GetScreenEndTime() - viewInfo.hpos;
634 double newh = origLeft + (origWidth - newDuration) / 2;
635
636 // MM: Commented this out because it was confusing users
637 /*
638 // make sure that the *right-hand* end of the selection is
639 // no further *left* than 1/3 of the way across the screen
640 if (viewInfo.selectedRegion.t1() < newh + viewInfo.screen / 3)
641 newh = viewInfo.selectedRegion.t1() - viewInfo.screen / 3;
642
643 // make sure that the *left-hand* end of the selection is
644 // no further *right* than 2/3 of the way across the screen
645 if (viewInfo.selectedRegion.t0() > newh + viewInfo.screen * 2 / 3)
646 newh = viewInfo.selectedRegion.t0() - viewInfo.screen * 2 / 3;
647 */
648
649 SetHorizontalThumb(newh);
650}
651
652void Viewport::ZoomAboutCenter(double multiplier)
653{
654 auto &project = mProject;
655 auto &viewInfo = ViewInfo::Get( project );
656
657 //Zoom() may change these, so record original values:
658 const double origLeft = viewInfo.hpos;
659 const double origWidth = viewInfo.GetScreenEndTime() - origLeft;
660
661 ZoomBy(multiplier);
662 const double newWidth = viewInfo.GetScreenEndTime() - viewInfo.hpos;
663
664 const double newh = origLeft + (origWidth - newWidth) / 2;
665 // newh = (newh > 0) ? newh : 0;
666 SetHorizontalThumb(newh);
667}
668
670{
671 auto &project = mProject;
673 auto &viewInfo = ViewInfo::Get(project);
674
675 const double end = tracks.GetEndTime();
676 const double start = 0;
677 const double len = end - start;
678
679 if (len <= 0.0)
680 return viewInfo.GetZoom();
681
682 auto w = viewInfo.GetTracksUsableWidth();
683 w -= 10;
684 return w/len;
685}
686
688{
689 auto &project = mProject;
690 auto &viewInfo = ViewInfo::Get(project);
692
693 const double start = 0;
694
696 SetHorizontalThumb(start);
697}
698
700{
701 if (!mpCallbacks)
702 return;
703 auto &project = mProject;
704 auto &viewInfo = ViewInfo::Get(project);
706
707 // Only nonminimized audio tracks will be resized
708 // Assume all channels of the track have the same minimization state
709 auto range = tracks.Any<AudioTrack>()
710 - [this](const Track *pTrack){
711 return mpCallbacks->IsTrackMinimized(*pTrack); };
712 auto count = static_cast<int>(range.sum(&Track::NChannels));
713 if (count == 0)
714 return;
715
716 // Find total height to apportion
717 auto height = viewInfo.GetHeight();
718 height -= 28;
719
720 // The height of minimized and non-audio tracks cannot be apportioned
721 const auto fn = [this](const Track *pTrack){
722 return mpCallbacks->GetTrackHeight(*pTrack);
723 };
724 height -= tracks.Any().sum(fn) - range.sum(fn);
725 height /= count;
726 height = std::max<int>(mpCallbacks->MinimumTrackHeight(), height);
727 for (auto t : range)
728 mpCallbacks->SetChannelHeights(*t, height);
729
730 ScrollToTop();
731}
732
734{
735 if (!mpCallbacks)
736 return;
737 auto &project = mProject;
739 for (auto t : tracks)
740 mpCallbacks->SetMinimized(*t, false);
741}
742
744{
745 if (!mpCallbacks)
746 return;
747 auto &project = mProject;
749 for (auto t : tracks)
750 mpCallbacks->SetMinimized(*t, true);
751}
752
754{
755 // Delay it until after channel views update their Y coordinates in response
756 // to TrackList mesages
757 BasicUI::CallAfter([wthis = weak_from_this()]{
758 if (auto This = wthis.lock()) {
759 This->UpdateScrollbarsForTracks();
760 This->Publish({ true, false, false });
761 }
762 });
763}
764
766{
767 if (mpCallbacks)
768 mpCallbacks->SetToDefaultSize();
769}
770
772{
773 Redraw();
774}
775
777{
778 HandleResize();
779 Redraw();
780}
781
783{
784 HandleResize();
785 // Redraw(); // Should we do this here too?
786}
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:699
void OnScrollLeftButton()
Definition: Viewport.cpp:144
void ZoomAboutSelection(double multiplier)
Definition: Viewport.cpp:583
void ScrollToBottom()
Definition: Viewport.cpp:556
void SetCallbacks(std::unique_ptr< ViewportCallbacks > pCallbacks)
Definition: Viewport.cpp:64
void CollapseAllTracks()
Definition: Viewport.cpp:743
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:733
void Zoom(double pixelsPerSecond)
Set timeline magnification; unchanged left edge time.
Definition: Viewport.cpp:497
bool mbInitializingScrollbar
Definition: Viewport.h:215
void Redraw()
Definition: Viewport.cpp:753
Viewport(AudacityProject &project)
Definition: Viewport.cpp:43
void ShowTrack(const Track &track)
Definition: Viewport.cpp:460
void ZoomFitHorizontally()
Definition: Viewport.cpp:687
void OnScrollRightButton()
Definition: Viewport.cpp:161
void OnScroll()
Definition: Viewport.cpp:403
void ScrollToEnd(bool extend)
Definition: Viewport.cpp:541
void ScrollToTop()
Definition: Viewport.cpp:534
void SetToDefaultSize()
Send a message to the main window PARENT of the viewport, to resize.
Definition: Viewport.cpp:765
void OnUndoRedo()
Definition: Viewport.cpp:776
void ZoomBy(double multiplier)
Multiply the magnification; unchanged left edge time.
Definition: Viewport.cpp:515
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:443
void HandleResize()
Definition: Viewport.cpp:393
void ScrollToStart(bool extend)
Definition: Viewport.cpp:523
void DoScroll()
Cause refresh of viewport contents after setting scrolling or zooming.
Definition: Viewport.cpp:421
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:652
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:771
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:782
double GetZoomOfToFit() const
Find pixels-per-second that would fit all tracks on the timeline.
Definition: Viewport.cpp:669
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:214
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:202
void Yield()
Dispatch waiting events, including actions enqueued by CallAfter.
Definition: BasicUI.cpp:225
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