Audacity 3.2.0
ScreenshotCommand.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity - A Digital Audio Editor
4 Copyright 1999-2018 Audacity Team
5 License: GPL v2 or later - see LICENSE.txt
6
7 Dominic Mazzoni
8 Dan Horgan
9 James Crook
10
11******************************************************************//*******************************************************************/
19
20
21#include "ScreenshotCommand.h"
22
23#include <mutex>
24#include <thread>
25
26#include "LoadCommands.h"
27#include "Project.h"
28#include <wx/app.h>
29#include <wx/toplevel.h>
30#include <wx/dcscreen.h>
31#include <wx/dcmemory.h>
32#include <wx/settings.h>
33#include <wx/bitmap.h>
34#include <wx/valgen.h>
35
36#include "../AdornedRulerPanel.h"
37#include "../TrackPanel.h"
38#include "../toolbars/ToolManager.h"
39#include "Prefs.h"
40#include "../ProjectWindow.h"
41#include "../Shuttle.h"
42#include "../ShuttleGui.h"
43#include "Track.h"
44#include "../widgets/VetoDialogHook.h"
45#include "CommandContext.h"
46#include "CommandManager.h"
47#include "CommandDispatch.h"
48
50{ XO("Screenshot") };
51
53
54
55static const EnumValueSymbol
57{
58 { XO("Window") },
59 { wxT("FullWindow"), XO("Full Window") },
60 { wxT("WindowPlus"), XO("Window Plus") },
61 { XO("Fullscreen") },
62 { XO("Toolbars") },
63 { XO("Effects") },
64 { XO("Scriptables") },
65 { XO("Preferences") },
66 { XO("Selectionbar") },
67 { wxT("SpectralSelection"), XO("Spectral Selection") },
68 { XO("Timer") },
69 { XO("Tools") },
70 { XO("Transport") },
71 { XO("Mixer") },
72 { XO("Meter") },
73 { wxT("PlayMeter"), XO("Play Meter") },
74 { wxT("RecordMeter"), XO("Record Meter") },
75 { XO("Edit") },
76 { XO("Device") },
77 { XO("Scrub") },
78 { XO("Play-at-Speed") },
79 { XO("Trackpanel") },
80 { XO("Ruler") },
81 { XO("Tracks") },
82 { wxT("FirstTrack"), XO("First Track") },
83 { wxT("FirstTwoTracks"), XO("First Two Tracks") },
84 { wxT("FirstThreeTracks"), XO("First Three Tracks") },
85 { wxT("FirstFourTracks"), XO("First Four Tracks") },
86 { wxT("SecondTrack"), XO("Second Track") },
87 { wxT("TracksPlus"), XO("Tracks Plus") },
88 { wxT("FirstTrackPlus"), XO("First Track Plus") },
89 { wxT("AllTracks"), XO("All Tracks") },
90 { wxT("AllTracksPlus"), XO("All Tracks Plus") },
91};
92
93
94static const EnumValueSymbol
96{
97 // These are acceptable dual purpose internal/visible names
98 { XO("Blue") },
99 /* i18n-hint: This really means the color, not as in "white noise" */
100 { XC("White", "color") },
101 { XO("None") },
102};
103
104
106{
107 mbBringToTop=true;
108 mIgnore=NULL;
109
110 static VetoDialogHook::Scope scope{ MayCapture };
111}
112
113template<bool Const>
115 S.Define( mPath, wxT("Path"), wxString{});
116 S.DefineEnum( mWhat, wxT("CaptureWhat"), kwindow,kCaptureWhatStrings, nCaptureWhats );
117 S.DefineEnum( mBack, wxT("Background"), kNone, kBackgroundStrings, nBackgrounds );
118 S.Define( mbBringToTop, wxT("ToTop"), true );
119 return true;
120};
121
123 { return VisitSettings<false>(S); }
124
126 { return VisitSettings<true>(S); }
127
129{
130 S.AddSpace(0, 5);
131
132 S.StartMultiColumn(2, wxALIGN_CENTER);
133 {
134 S.TieTextBox( XXO("Path:"), mPath);
135 S.TieChoice( XXO("Capture What:"),
137 S.TieChoice( XXO("Background:"),
139 S.TieCheckBox( XXO("Bring To Top"), mbBringToTop);
140 }
141 S.EndMultiColumn();
142}
143
144// static member variable.
145void (*ScreenshotCommand::mIdleHandler)(wxIdleEvent& event) = NULL;
147// This static variable is used to get from an idle event to the screenshot
148// command that caused the idle event interception to be set up.
150
151// IdleHandler is expected to be called from EVT_IDLE when a dialog has been
152// fully created. Usually the dialog will have been created by invoking
153// an effects gui.
154void IdleHandler(wxIdleEvent& event){
155 event.Skip();
156 wxWindow * pWin = dynamic_cast<wxWindow*>(event.GetEventObject());
157 wxASSERT( pWin );
158 pWin->Unbind(wxEVT_IDLE, IdleHandler);
160 // We have the relevant window, so go and capture it.
163}
164
166{
168 pIdleHandlerProject = &project;
169}
170
172{
173 wxWindow *front = NULL;
174 wxWindow *proj = wxGetTopLevelParent( ProjectWindow::Find( project ) );
175
176 for (auto & win : wxTopLevelWindows)
177 {
178 win = wxGetTopLevelParent(win);
179 if (win != mIgnore && win != proj && win->IsShown()) {
180 front = win;
181 break;
182 }
183 }
184
185 if (!front || !front->IsTopLevel()) {
186 return (wxTopLevelWindow *)proj;
187 }
188
189 return (wxTopLevelWindow *)front;
190}
191
193{
194 wxRect r;
195
196 r.x = 16;
197 r.y = 16;
198 r.width = r.x * 2;
199 r.height = r.y * 2;
200
201 return r;
202}
203
204static void Yield()
205{
206 using namespace std::chrono;
207 int cnt;
208 for (cnt = 10; cnt && !wxTheApp->Yield(true); cnt--)
209 std::this_thread::sleep_for(10ms);
210 std::this_thread::sleep_for(200ms);
211 for (cnt = 10; cnt && !wxTheApp->Yield(true); cnt--)
212 std::this_thread::sleep_for(10ms);
213}
214
216 const CommandContext & context,
217 const wxString &filename,
218 wxWindow *window, wxRect r,
219 bool bg)
220{
221 int width = r.width;
222 int height = r.height;
223 if( r.width == 0 )
224 return false;
225 if (window ) {
226 wxWindow * win = window;
227 wxTopLevelWindow * top_win= nullptr;
228 if( !window->IsTopLevel())
229 win = wxGetTopLevelParent(window);
230 top_win = dynamic_cast<wxTopLevelWindow*>( win );
231 if( (!bHasBringToTop || mbBringToTop) && (!top_win || !top_win->IsActive()) ){
232 win->Raise();
233 Yield();
234 }
235 }
236
237
238 int screenW, screenH;
239 wxDisplaySize(&screenW, &screenH);
240 // Bug 1378 workaround.
241 // wx 3.0.2 has a bug in Blit from ScreenDC where in default mode
242 // much is drawn transparent - including for example black text!
243 // Forcing 24 bit here is a workaround.
244 wxBitmap full(screenW, screenH, 24);
245
246 wxScreenDC screenDC;
247 wxMemoryDC fullDC;
248
249#if defined(__WXMAC__) && !wxCHECK_VERSION(3, 0, 0)
250 full = DoGetAsBitmap(NULL);
251#else
252 // We grab the whole screen image since there seems to be a problem with
253 // using non-zero source coordinates on OSX. (as of wx2.8.9)
254 fullDC.SelectObject(full);
255 fullDC.Blit(0, 0, screenW, screenH, &screenDC, 0, 0);
256 fullDC.SelectObject(wxNullBitmap);
257#endif
258
259 //wxRect r(x, y, width, height);
260
261
262 // Convert to screen coordinates if needed
263 if (window && window->GetParent() && !window->IsTopLevel()) {
264 r.SetPosition(window->GetParent()->ClientToScreen(r.GetPosition()));
265 }
266
267 // Ensure within bounds (x/y are negative on Windows when maximized)
268 r.Intersect(wxRect(0, 0, screenW, screenH));
269
270 // Extract the actual image
271 wxBitmap part = full.GetSubBitmap(r);
272
273 // Add a background
274 if (bg && mBackground) {
275 wxRect b = GetBackgroundRect();
276
277 wxBitmap back(width + b.width, height + b.height);
278 fullDC.SelectObject(back);
279
280 fullDC.SetBackground(wxBrush(mBackColor, wxBRUSHSTYLE_SOLID));
281 fullDC.Clear();
282
283 fullDC.DrawBitmap(part, b.x, b.y);
284 fullDC.SelectObject(wxNullBitmap);
285
286 part = back;
287 }
288
289 // Save the final image
290 wxImage image = part.ConvertToImage();
291 ::wxBell();
292
293 if (image.SaveFile(filename)) {
294 // flush
295 context.Status( wxString::Format( _("Saved %s"), filename ), true );
296 }
297 else {
298 context.Error(
299 wxString::Format( _("Error trying to save file: %s"), filename ) );
300 return false;
301 }
302 return true;
303}
304
306 const CommandContext & context,
307 ToolManager *man, int type, const wxString &name)
308{
309 bool visible = man->IsVisible(type);
310 if (!visible) {
311 man->ShowHide(type);
312 Yield();
313 }
314
315 wxWindow *w = man->GetToolBar(type);
316 int x = 0, y = 0;
317 int width, height;
318
319 w->ClientToScreen(&x, &y);
320 w->GetParent()->ScreenToClient(&x, &y);
321 w->GetClientSize(&width, &height);
322
323 bool result = Capture(context, name, w, wxRect(x, y, width, height));
324
325 if (!visible) {
326 man->ShowHide(type);
327 if (mIgnore)
328 mIgnore->Raise();
329 }
330 return result;
331}
332
334 const CommandContext & context,
335 wxWindow *win, const wxString &FileName)
336{
337 int x = 0, y = 0;
338 int width, height;
339
340 win->ClientToScreen(&x, &y);
341 win->GetParent()->ScreenToClient(&x, &y);
342 win->GetClientSize(&width, &height);
343
344 return Capture(context, FileName, win, wxRect(x, y, width, height));
345}
346
347// Handed a dialog, which it is given the option to capture.
348bool ScreenshotCommand::MayCapture( wxDialog * pDlg )
349{
350 if( mIdleHandler == NULL )
351 return false;
352 pDlg->Bind( wxEVT_IDLE, mIdleHandler );
353 mIdleHandler = NULL;
354 pDlg->ShowModal();
355 return true;
356}
357
359 const CommandContext & context,
360 wxWindow * pWin )
361{
362 using namespace std::chrono;
363 wxDialog * pDlg = dynamic_cast<wxDialog*>(pWin);
364 if( !pDlg ){
365 wxLogDebug("Event from bogus dlg" );
366 return;
367 }
368
369 wxPoint Pos = pDlg->GetScreenPosition();
370 wxSize Siz = pDlg->GetSize();
371 wxString Title = pDlg->GetTitle();
372
373 // Remove '/' from "Sliding Time Scale/Pitch Shift..."
374 // and any other effects that have illegal filename characters.
375 Title.Replace( "/", "" );
376 Title.Replace( ":", "" );
377 wxString Name = mDirToWriteTo + Title + ".png";
378
379 wxLogDebug("Taking screenshot of window %s (%i,%i,%i,%i)", Name,
380 Pos.x, Pos.y, Siz.x, Siz.y );
381 // This delay is needed, as dialogs take a moment or two to fade in.
382 std::this_thread::sleep_for(400ms);
383 // JKC: The border of 7 pixels was determined from a trial capture and then measuring
384 // in the GIMP. I'm unsure where the border comes from.
385 Capture( context, Name, pDlg, wxRect((int)Pos.x+7, (int)Pos.y, (int)Siz.x-14, (int)Siz.y-7) );
386
387 // We've captured the dialog, so now dismiss the dialog.
388 wxCommandEvent Evt( wxEVT_BUTTON, wxID_CANCEL );
389 pDlg->GetEventHandler()->AddPendingEvent( Evt );
390}
391
393 const CommandContext & context,
394 AudacityProject * pProject, const wxString &FileName )
395{
396 using namespace std::chrono;
397 (void)&FileName;//compiler food.
398 (void)&context;
399 CommandManager &commandManager = CommandManager::Get( *pProject );
400
401 // Yucky static variables. Is there a better way? The problem is that we need the
402 // idle callback to know more about what to do.
403#ifdef __WXMSW__
404 mDirToWriteTo = FileName.BeforeLast('\\') + "\\";
405#else
406 mDirToWriteTo = FileName.BeforeLast('/') + "/";
407#endif
408 mpShooter = this;
409 const int nPrefsPages = 19;
410
411 for( int i=0;i<nPrefsPages;i++){
412 // The handler is cleared each time it is used.
413 SetIdleHandler( context.project );
414 gPrefs->Write(wxT("/Prefs/PrefsCategory"), (long)i);
415 gPrefs->Flush();
416 CommandID Command{ wxT("Preferences") };
417 const CommandContext projectContext( *pProject );
418 if( !::HandleTextualCommand( commandManager,
419 Command, projectContext, AlwaysEnabledFlag, true ) )
420 {
421 // using GET in a log message for devs' eyes only
422 wxLogDebug("Command %s not found", Command.GET() );
423 }
424 // This sleep is not needed, but gives user a chance to see the
425 // dialogs as they whizz by.
426 std::this_thread::sleep_for(200ms);
427 }
428}
429
431 const CommandContext & context,
432 AudacityProject * pProject, const wxString &FileName )
433{
434 (void)pProject;
435 (void)&FileName;//compiler food.
436 (void)&context;
437#define TRICKY_CAPTURE
438#define CAPTURE_NYQUIST_TOO
439 // Commented out the effects that don't have dialogs.
440 // Also any problematic ones,
441 CaptureCommands( context, {
442#ifdef TRICKY_CAPTURE
443 //"Contrast...", // renamed
444 "ContrastAnalyser",
445 //"Plot Spectrum...", // renamed
446 "PlotSpectrum",
447
448 "Auto Duck...", // needs a track below.
449 //"Spectral edit multi tool",
450 "Spectral edit parametric EQ...", // Needs a spectral selection.
451 "Spectral edit shelves...",
452
453 //"Noise Reduction...", // Exits twice...
454 //"SC4...", //Has 'Close' rather than 'Cancel'.
455#endif
456 "Amplify...",
457 "Bass and Treble...",
458 "Change Pitch...",
459 "Change Speed...",
460 "Change Tempo...",
461 "Click Removal...",
462 "Compressor...",
463 "Distortion...",
464 "Echo...",
465 //"Equalization...",
466 "Filter Curve EQ...",
467 "Graphic EQ...",
468 //"Fade In",
469 //"Fade Out",
470 //"Invert",
471 "Normalize...",
472 "Paulstretch...",
473 "Phaser...",
474 //"Repair",
475 "Repeat...",
476 "Reverb...",
477 //"Reverse",
478 "Sliding Stretch...",
479 "Truncate Silence...",
480 "Wahwah...",
481 // Sole LADSPA effect...
482#ifdef CAPTURE_NYQUIST_TOO
483 "Adjustable Fade...",
484 "Clip Fix...",
485 //"Crossfade Clips",
486 "Crossfade Tracks...",
487 "Delay...",
488 "High Pass Filter...",
489 "Limiter...",
490 "Low Pass Filter...",
491 "Notch Filter...",
492 "Nyquist Effects Prompt...",
493 //"Studio Fade Out",
494 "Tremolo...",
495 "Vocal Reduction and Isolation...",
496 "Vocal Remover...",
497 "Vocoder...",
498#endif
499 // Generators.....
500 "Chirp...",
501 "DTMF Tones...",
502 "Noise...",
503 "Silence...",
504 "Tone...",
505#ifdef CAPTURE_NYQUIST_TOO
506 "Pluck...",
507 "Rhythm Track...",
508 "Risset Drum...",
509 "Sample Data Import...",
510#endif
511 // Analyzers...
512 "Find Clipping...",
513#ifdef CAPTURE_NYQUIST_TOO
514 "Beat Finder...",
515 "Label Sounds...",
516 "Regular Interval Labels...",
517 "Sample Data Export...",
518#endif
519 } );
520}
521
523 const CommandContext & context,
524 AudacityProject * pProject, const wxString &FileName )
525{
526 (void)pProject;
527 (void)&FileName;//compiler food.
528 (void)&context;
529
530 CaptureCommands( context, {
531 "SelectTime",
532 "SelectFrequencies",
533 "SelectTracks",
534 "SetTrackStatus",
535 "SetTrackAudio",
536 "SetTrackVisuals",
537 "GetPreference",
538 "SetPreference",
539 "SetClip",
540 "SetEnvelope",
541 "SetLabel",
542 "SetProject",
543
544 "Select",
545 "SetTrack",
546 "GetInfo",
547 "Message",
548 "Help", // Help on individual commands
549 "Import2",
550 "Export2",
551 "OpenProject2",
552 "SaveProject2",
553 "Drag",
554 "CompareAudio",
555 "Screenshot",
556 } );
557
558}
559
560
562 const CommandContext & context, const wxArrayStringEx & Commands )
563{
564 using namespace std::chrono;
565 AudacityProject * pProject = &context.project;
567 wxString Str;
568 // Yucky static variables. Is there a better way? The problem is that we need the
569 // idle callback to know more about what to do.
570#ifdef __WXMSW__
571 mDirToWriteTo = mFileName.BeforeLast('\\') + "\\";
572#else
573 mDirToWriteTo = mFileName.BeforeLast('/') + "/";
574#endif
575 mpShooter = this;
576
577 for( size_t i=0;i<Commands.size();i++){
578 // The handler is cleared each time it is used.
579 SetIdleHandler( context.project );
580 Str = Commands[i];
581 const CommandContext projectContext( *pProject );
582 if( !manager.HandleTextualCommand( Str, projectContext, AlwaysEnabledFlag, true ) )
583 {
584 wxLogDebug("Command %s not found", Str);
585 }
586 // This particular sleep is not needed, but gives user a chance to see the
587 // dialogs as they whizz by.
588 std::this_thread::sleep_for(200ms);
589 }
590}
591
592wxString ScreenshotCommand::MakeFileName(const wxString &path, const wxString &basename)
593{
594 // If the path is a full file name, then use it.
595 if( path.EndsWith( ".png" ) )
596 return path;
597
598 // Otherwise make up a file name that has not been used already.
599 wxFileName prefixPath;
600 prefixPath.AssignDir(path);
601 wxString prefix = prefixPath.GetPath
602 (wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR);
603
604 wxString filename;
605 int i = 0;
606 do {
607 filename.Printf(wxT("%s%s%03d.png"),
608 prefix, basename, i);
609 i++;
610 } while (::wxFileExists(filename));
611
612 return filename;
613}
614
616{
617 // Read the parameters that were passed in
620
621 // Build a suitable filename
623 kCaptureWhatStrings[ mCaptureMode ].Translation() );
624
625 if (mBack == kBlue)
626 {
627 mBackground = true;
628 mBackColor = wxColour(51, 102, 153);
629 }
630 else if (mBack == kWhite)
631 {
632 mBackground = true;
633 mBackColor = wxColour(255, 255, 255);
634 }
635 else
636 {
637 mBackground = false;
638 }
639
640}
641
642wxRect ScreenshotCommand::GetWindowRect(wxTopLevelWindow *w){
643 int x = 0, y = 0;
644 int width, height;
645
646 w->ClientToScreen(&x, &y);
647 w->GetClientSize(&width, &height);
648 return wxRect( x,y,width,height);
649}
650
651wxRect ScreenshotCommand::GetFullWindowRect(wxTopLevelWindow *w){
652
653 wxRect r = w->GetRect();
654 r.SetPosition(w->GetScreenPosition());
655 r = w->GetScreenRect();
656
657#if defined(__WXGTK__)
658 // In wxGTK, we need to include decoration sizes
659 r.width += (wxSystemSettings::GetMetric(wxSYS_BORDER_X, w) * 2);
660 r.height += wxSystemSettings::GetMetric(wxSYS_CAPTION_Y, w) +
661 wxSystemSettings::GetMetric(wxSYS_BORDER_Y, w);
662#endif
664 {
665 // background colour not selected but we want a background
666 wxRect b = GetBackgroundRect();
667 r.x = (r.x - b.x) >= 0 ? (r.x - b.x): 0;
668 r.y = (r.y - b.y) >= 0 ? (r.y - b.y): 0;
669 r.width += b.width;
670 r.height += b.height;
671 }
672
673 return r;
674}
675
677 int width, height;
678 wxDisplaySize(&width, &height);
679
680 return wxRect( 0,0,width,height);
681}
682
684 //AdornedRulerPanel *ruler = panel->mRuler;
685
686 int h = panel->GetRuler()->GetRulerHeight();
687 int x = 0, y = -h;
688 int width, height;
689
690 panel->ClientToScreen(&x, &y);
691 panel->GetParent()->ScreenToClient(&x, &y);
692 panel->GetClientSize(&width, &height);
693 return wxRect(x, y, width, height + h);
694}
695
697 int x = 0, y = 0;
698 int width, height;
699
700 ruler->ClientToScreen(&x, &y);
701 ruler->GetParent()->ScreenToClient(&x, &y);
702 ruler->GetClientSize(&width, &height);
703 height = ruler->GetRulerHeight();
704 return wxRect( x, y, width, height);
705}
706
708 int x = 0, y = 0;
709 int width, height;
710
711 panel->ClientToScreen(&x, &y);
712 panel->GetParent()->ScreenToClient(&x, &y);
713 panel->GetClientSize(&width, &height);
714
715 return wxRect( x, y, width, height);
716}
717
719 auto FindRectangle = []( TrackPanel &panel, Track &t )
720 {
721 wxRect rect = panel.FindFocusedTrackRect( &t );
722
723 // Reposition it relative to parent of panel
724 rect.SetPosition(
725 panel.GetParent()->ScreenToClient(
726 panel.ClientToScreen(
727 rect.GetPosition())));
728
729 return rect;
730 };
731
732 int count = 0;
733 for (auto t : TrackList::Get( *pProj ).Leaders()) {
734 count += 1;
735 if( count > n )
736 {
737 wxRect r = FindRectangle( *panel, *t );
738 return r;
739 }
740 }
741 return wxRect( 0,0,0,0);
742}
743
744wxString ScreenshotCommand::WindowFileName(AudacityProject * proj, wxTopLevelWindow *w){
745 if (w != ProjectWindow::Find( proj ) && !w->GetTitle().empty()) {
747 kCaptureWhatStrings[ mCaptureMode ].Translation() +
748 (wxT("-") + w->GetTitle() + wxT("-")));
749 }
750 return mFileName;
751}
752
754{
756 //Don't reset the toolbars to a known state.
757 //We will be capturing variations of them.
758 //ToolManager::Get( context.project ).Reset();
759
760 wxTopLevelWindow *w = GetFrontWindow(&context.project);
761 if (!w)
762 return false;
763
764 TrackPanel *panel = &TrackPanel::Get( context.project );
765 AdornedRulerPanel *ruler = panel->GetRuler();
766
767 int nTracks = TrackList::Get( context.project ).size();
768
769 int x1,y1,x2,y2;
770 w->ClientToScreen(&x1, &y1);
771 panel->ClientToScreen(&x2, &y2);
772
773 wxPoint p( x2-x1, y2-y1);
774
775 auto &toolManager = ToolManager::Get( context.project );
776
777 switch (mCaptureMode) {
778 case kwindow:
779 return Capture(context, WindowFileName( &context.project, w ) , w, GetWindowRect(w));
780 case kfullwindow:
781 case kwindowplus:
782 return Capture(context, WindowFileName( &context.project, w ) , w, GetFullWindowRect(w));
783 case kfullscreen:
784 return Capture(context, mFileName, w,GetScreenRect());
785 case ktoolbars:
786 return CaptureDock(context, toolManager.GetTopDock(), mFileName);
787 case kscriptables:
788 CaptureScriptables(context, &context.project, mFileName);
789 break;
790 case keffects:
791 CaptureEffects(context, &context.project, mFileName);
792 break;
793 case kpreferences:
794 CapturePreferences(context, &context.project, mFileName);
795 break;
796 case kselectionbar:
797 return CaptureToolbar(context, &toolManager, SelectionBarID, mFileName);
799 return CaptureToolbar(context, &toolManager, SpectralSelectionBarID, mFileName);
800 case ktimer:
801 return CaptureToolbar(context, &toolManager, TimeBarID, mFileName);
802 case ktools:
803 return CaptureToolbar(context, &toolManager, ToolsBarID, mFileName);
804 case ktransport:
805 return CaptureToolbar(context, &toolManager, TransportBarID, mFileName);
806 case kmixer:
807 return CaptureToolbar(context, &toolManager, MixerBarID, mFileName);
808 case kmeter:
809 return CaptureToolbar(context, &toolManager, MeterBarID, mFileName);
810 case krecordmeter:
811 return CaptureToolbar(context, &toolManager, RecordMeterBarID, mFileName);
812 case kplaymeter:
813 return CaptureToolbar(context, &toolManager, PlayMeterBarID, mFileName);
814 case kedit:
815 return CaptureToolbar(context, &toolManager, EditBarID, mFileName);
816 case kdevice:
817 return CaptureToolbar(context, &toolManager, DeviceBarID, mFileName);
818 case ktranscription:
819 return CaptureToolbar(context, &toolManager, TranscriptionBarID, mFileName);
820 case kscrub:
821 return CaptureToolbar(context, &toolManager, ScrubbingBarID, mFileName);
822 case ktrackpanel:
823 return Capture(context, mFileName, panel, GetPanelRect(panel));
824 case kruler:
825 return Capture(context, mFileName, ruler, GetRulerRect(ruler) );
826 case ktracks:
827 return Capture(context, mFileName, panel, GetTracksRect(panel));
828 case kfirsttrack:
829 return Capture(context, mFileName, panel, GetTrackRect( &context.project, panel, 0 ) );
830 case ksecondtrack:
831 return Capture(context, mFileName, panel, GetTrackRect( &context.project, panel, 1 ) );
832 case ktracksplus:
833 { wxRect r = GetTracksRect(panel);
834 r.SetTop( r.GetTop() - ruler->GetRulerHeight() );
835 r.SetHeight( r.GetHeight() + ruler->GetRulerHeight() );
836 return Capture(context, mFileName, panel, r);
837 }
838 case kfirsttrackplus:
839 { wxRect r = GetTrackRect(&context.project, panel, 0 );
840 r.SetTop( r.GetTop() - ruler->GetRulerHeight() );
841 r.SetHeight( r.GetHeight() + ruler->GetRulerHeight() );
842 return Capture(context, mFileName, panel, r );
843 }
844 case kfirsttwotracks:
845 { wxRect r = GetTrackRect( &context.project, panel, 0 );
846 r = r.Union( GetTrackRect( &context.project, panel, 1 ));
847 return Capture(context, mFileName, panel, r );
848 }
850 { wxRect r = GetTrackRect( &context.project, panel, 0 );
851 r = r.Union( GetTrackRect( &context.project, panel, 2 ));
852 return Capture(context, mFileName, panel, r );
853 }
854 case kfirstfourtracks:
855 { wxRect r = GetTrackRect( &context.project, panel, 0 );
856 r = r.Union( GetTrackRect( &context.project, panel, 3 ));
857 return Capture(context, mFileName, panel, r );
858 }
859 case kalltracks:
860 { wxRect r = GetTrackRect( &context.project, panel, 0 );
861 r = r.Union( GetTrackRect( &context.project, panel, nTracks-1 ));
862 return Capture(context, mFileName, panel, r );
863 }
864 case kalltracksplus:
865 { wxRect r = GetTrackRect( &context.project, panel, 0 );
866 r.SetTop( r.GetTop() - ruler->GetRulerHeight() );
867 r.SetHeight( r.GetHeight() + ruler->GetRulerHeight() );
868 r = r.Union( GetTrackRect( &context.project, panel, nTracks-1 ));
869 return Capture(context, mFileName, panel, r );
870 }
871 default:
872 return false;
873 }
874
875 return true;
876}
bool HandleTextualCommand(CommandManager &commandManager, const CommandID &Str, const CommandContext &context, CommandFlag flags, bool alwaysEnabled)
constexpr CommandFlag AlwaysEnabledFlag
Definition: CommandFlag.h:35
static TransactionScope::Factory::Scope scope
const TranslatableString name
Definition: Distortion.cpp:82
#define XXO(s)
Definition: Internat.h:44
#define XO(s)
Definition: Internat.h:31
#define XC(s, c)
Definition: Internat.h:37
#define _(s)
Definition: Internat.h:75
FileConfig * gPrefs
Definition: Prefs.cpp:71
static const AttachedProjectObjects::RegisteredFactory manager
static AudacityProject * pIdleHandlerProject
static const EnumValueSymbol kBackgroundStrings[ScreenshotCommand::nBackgrounds]
static const EnumValueSymbol kCaptureWhatStrings[ScreenshotCommand::nCaptureWhats]
void IdleHandler(wxIdleEvent &event)
static void Yield()
TranslatableStrings Msgids(const EnumValueSymbol strings[], size_t nStrings)
Convenience function often useful when adding choice controls.
#define S(N)
Definition: ToChars.cpp:64
@ ScrubbingBarID
Definition: ToolBar.h:80
@ RecordMeterBarID
Definition: ToolBar.h:75
@ PlayMeterBarID
Definition: ToolBar.h:76
@ DeviceBarID
Definition: ToolBar.h:81
@ SelectionBarID
Definition: ToolBar.h:82
@ TranscriptionBarID
Definition: ToolBar.h:79
@ TimeBarID
Definition: ToolBar.h:86
@ TransportBarID
Definition: ToolBar.h:72
@ MeterBarID
Definition: ToolBar.h:74
@ MixerBarID
Definition: ToolBar.h:77
@ ToolsBarID
Definition: ToolBar.h:73
@ EditBarID
Definition: ToolBar.h:78
declares abstract base class Track, TrackList, and iterators over TrackList
This is an Audacity Specific ruler panel which additionally has border, selection markers,...
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:89
CommandContext provides additional information to an 'Apply()' command. It provides the project,...
virtual void Error(const wxString &message) const
virtual void Status(const wxString &message, bool bFlush=false) const
AudacityProject & project
CommandManager implements a system for organizing all user-callable commands.
static CommandManager & Get(AudacityProject &project)
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
static ProjectWindow * Find(AudacityProject *pProject)
Implements a command for capturing various areas of the screen or project window. It's one big if-els...
static ScreenshotCommand * mpShooter
static bool MayCapture(wxDialog *pDlg)
bool CaptureToolbar(const CommandContext &Context, ToolManager *man, int type, const wxString &name)
wxRect GetTracksRect(TrackPanel *panel)
void CaptureScriptables(const CommandContext &Context, AudacityProject *pProject, const wxString &fileName)
void CaptureWindowOnIdle(const CommandContext &context, wxWindow *pWin)
static void SetIdleHandler(AudacityProject &project)
static void(* mIdleHandler)(wxIdleEvent &event)
wxRect GetRulerRect(AdornedRulerPanel *ruler)
bool VisitSettings(SettingsVisitorBase< Const > &S)
void PopulateOrExchange(ShuttleGui &S) override
bool Capture(const CommandContext &Context, const wxString &basename, wxWindow *window, wxRect rect, bool bg=false)
wxString WindowFileName(AudacityProject *proj, wxTopLevelWindow *w)
wxString MakeFileName(const wxString &path, const wxString &basename)
wxTopLevelWindow * GetFrontWindow(AudacityProject *project)
wxRect GetPanelRect(TrackPanel *panel)
wxRect GetTrackRect(AudacityProject *pProj, TrackPanel *panel, int n)
bool CaptureDock(const CommandContext &Context, wxWindow *win, const wxString &fileName)
void CaptureEffects(const CommandContext &Context, AudacityProject *pProject, const wxString &fileName)
wxRect GetWindowRect(wxTopLevelWindow *w)
void CapturePreferences(const CommandContext &Context, AudacityProject *pProject, const wxString &fileName)
wxRect GetFullWindowRect(wxTopLevelWindow *w)
bool Apply(const CommandContext &context) override
static const ComponentInterfaceSymbol Symbol
void CaptureCommands(const CommandContext &Context, const wxArrayStringEx &Commands)
Visitor of effect or command parameters. This is a base class with lots of virtual functions that do ...
Definition: Shuttle.h:115
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI.
Definition: ShuttleGui.h:631
class ToolManager
Definition: ToolManager.h:55
static ToolManager & Get(AudacityProject &project)
void ShowHide(int type)
bool IsVisible(int type)
ToolBar * GetToolBar(int type) const
Abstract base class for an object holding data associated with points on a time axis.
Definition: Track.h:225
auto Leaders() -> TrackIterRange< TrackType >
Definition: Track.h:1463
size_t size() const
Definition: Track.cpp:991
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:467
The TrackPanel class coordinates updates and operations on the main part of the screen which contains...
Definition: TrackPanel.h:65
AdornedRulerPanel * GetRuler()
Definition: TrackPanel.h:172
static TrackPanel & Get(AudacityProject &project)
Definition: TrackPanel.cpp:227
wxRect FindFocusedTrackRect(const Track *target)
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
std::unique_ptr< CommandItem > Command(const CommandID &name, const TranslatableString &label_in, void(Handler::*pmf)(const CommandContext &), CommandFlag flags, const CommandManager::Options &options={}, CommandHandlerFinder finder=FinderScope::DefaultFinder())
BuiltinCommandsModule::Registration< ScreenshotCommand > reg