1 /**********************************************************************
2 
3    Audacity - A Digital Audio Editor
4    Copyright 1999-2018 Audacity Team
5    License: wxWidgets
6 
7    James Crook
8 
9 ******************************************************************//**
10 
11 \file GetInfoCommand.cpp
12 \brief Contains definitions for GetInfoCommand class.
13 This class now lists
14 - Commands
15 - Menus
16 - Tracks
17 - Clips
18 - Labels
19 - Boxes
20 
21 *//*******************************************************************/
22 
23 
24 #include "GetInfoCommand.h"
25 
26 #include "LoadCommands.h"
27 #include "Project.h"
28 #include "../ProjectWindows.h"
29 #include "CommandManager.h"
30 #include "CommandTargets.h"
31 #include "../effects/EffectManager.h"
32 #include "../widgets/Overlay.h"
33 #include "../TrackPanelAx.h"
34 #include "../TrackPanel.h"
35 #include "../WaveClip.h"
36 #include "ViewInfo.h"
37 #include "../WaveTrack.h"
38 #include "../LabelTrack.h"
39 #include "../Envelope.h"
40 
41 #include "SelectCommand.h"
42 #include "../ShuttleGui.h"
43 #include "CommandContext.h"
44 
45 #include "../prefs/PrefsDialog.h"
46 #include "../Shuttle.h"
47 #include "../PluginManager.h"
48 #include "../tracks/ui/TrackView.h"
49 #include "../ShuttleGui.h"
50 
51 #include <wx/frame.h>
52 #include <wx/log.h>
53 #include <wx/menu.h>
54 
55 const ComponentInterfaceSymbol GetInfoCommand::Symbol
56 { XO("Get Info") };
57 
58 namespace{ BuiltinCommandsModule::Registration< GetInfoCommand > reg; }
59 enum {
60    kCommands,
61    //kCommandsPlus,
62    kMenus,
63    kPreferences,
64    kTracks,
65    kClips,
66    kEnvelopes,
67    kLabels,
68    kBoxes,
69    nTypes
70 };
71 
72 static const EnumValueSymbol kTypes[nTypes] =
73 {
74    { XO("Commands") },
75    //{ wxT("CommandsPlus"), XO("Commands Plus") },
76    { XO("Menus") },
77    { XO("Preferences") },
78    { XO("Tracks") },
79    { XO("Clips") },
80    { XO("Envelopes") },
81    { XO("Labels") },
82    { XO("Boxes") },
83 };
84 
85 enum {
86    kJson,
87    kLisp,
88    kBrief,
89    nFormats
90 };
91 
92 static const EnumValueSymbol kFormats[nFormats] =
93 {
94    // These are acceptable dual purpose internal/visible names
95 
96    /* i18n-hint JavaScript Object Notation */
97    { XO("JSON") },
98    /* i18n-hint name of a computer programming language */
99    { XO("LISP") },
100    { XO("Brief") }
101 };
102 
103 
104 
DefineParams(ShuttleParams & S)105 bool GetInfoCommand::DefineParams( ShuttleParams & S ){
106    S.DefineEnum( mInfoType, wxT("Type"), 0, kTypes, nTypes );
107    S.DefineEnum( mFormat, wxT("Format"), 0, kFormats, nFormats );
108    return true;
109 }
110 
PopulateOrExchange(ShuttleGui & S)111 void GetInfoCommand::PopulateOrExchange(ShuttleGui & S)
112 {
113    S.AddSpace(0, 5);
114 
115    S.StartMultiColumn(2, wxALIGN_CENTER);
116    {
117       S.TieChoice( XXO("Type:"),
118          mInfoType, Msgids( kTypes, nTypes ));
119       S.TieChoice( XXO("Format:"),
120          mFormat, Msgids( kFormats, nFormats ));
121    }
122    S.EndMultiColumn();
123 }
124 
Apply(const CommandContext & context)125 bool GetInfoCommand::Apply(const CommandContext &context)
126 {
127    if( mFormat == kJson )
128       return ApplyInner( context );
129 
130    if( mFormat == kLisp )
131    {
132       CommandContext LispyContext(
133          context.project,
134          std::make_unique<LispifiedCommandOutputTargets>( *context.pOutput.get() )
135          );
136       return ApplyInner( LispyContext );
137    }
138 
139    if( mFormat == kBrief )
140    {
141       CommandContext BriefContext(
142          context.project,
143          std::make_unique<BriefCommandOutputTargets>( *context.pOutput.get() )
144          );
145       return ApplyInner( BriefContext );
146    }
147 
148    return false;
149 }
150 
ApplyInner(const CommandContext & context)151 bool GetInfoCommand::ApplyInner(const CommandContext &context)
152 {
153    switch( mInfoType  ){
154       // flag of 1 to include parameterless commands.
155       case kCommands     : return SendCommands( context, 1 );
156       case kMenus        : return SendMenus( context );
157       case kPreferences  : return SendPreferences( context );
158       case kTracks       : return SendTracks( context );
159       case kClips        : return SendClips( context );
160       case kEnvelopes    : return SendEnvelopes( context );
161       case kLabels       : return SendLabels( context );
162       case kBoxes        : return SendBoxes( context );
163       default:
164          context.Status( "Command options not recognised" );
165    }
166    return false;
167 }
168 
SendMenus(const CommandContext & context)169 bool GetInfoCommand::SendMenus(const CommandContext &context)
170 {
171    wxMenuBar * pBar = GetProjectFrame( context.project ).GetMenuBar();
172    if(!pBar ){
173       wxLogDebug("No menus");
174       return false;
175    }
176 
177    size_t cnt = pBar->GetMenuCount();
178    size_t i;
179    wxString Label;
180    context.StartArray();
181    for(i=0;i<cnt;i++)
182    {
183       Label = pBar->GetMenuLabelText( i );
184       context.StartStruct();
185       context.AddItem( 0, "depth" );
186       context.AddItem( 0, "flags" );
187       context.AddItem( Label, "label" );
188       context.AddItem( "", "accel" );
189       context.EndStruct();
190       ExploreMenu( context, pBar->GetMenu( i ), pBar->GetId(), 1 );
191    }
192    context.EndArray();
193    return true;
194 }
195 
196 #include "Prefs.h"
197 
198 namespace {
199 
200 /**************************************************************************//**
201 \brief Shuttle that retrieves a JSON format definition of a command's parameters.
202 ********************************************************************************/
203 class ShuttleGuiGetDefinition : public ShuttleGui, public CommandMessageTargetDecorator
204 {
205 public:
206    ShuttleGuiGetDefinition(wxWindow * pParent,CommandMessageTarget & target );
207    virtual ~ShuttleGuiGetDefinition();
208 
209    wxCheckBox * TieCheckBox(
210       const TranslatableString &Prompt,
211       const BoolSetting &Setting) override;
212    wxCheckBox * TieCheckBoxOnRight(
213       const TranslatableString &Prompt,
214       const BoolSetting &Setting) override;
215 
216    wxChoice *TieChoice(
217       const TranslatableString &Prompt,
218       const ChoiceSetting &choiceSetting ) override;
219 
220    wxChoice * TieNumberAsChoice(
221       const TranslatableString &Prompt,
222       const IntSetting &Setting,
223       const TranslatableStrings & Choices,
224       const std::vector<int> * pInternalChoices, int iNoMatchSelector ) override;
225 
226    wxTextCtrl * TieTextBox(
227       const TranslatableString &Prompt,
228       const StringSetting &Setting,
229       const int nChars) override;
230    wxTextCtrl * TieIntegerTextBox(
231       const TranslatableString & Prompt,
232       const IntSetting &Setting,
233       const int nChars) override;
234    wxTextCtrl * TieNumericTextBox(
235       const TranslatableString & Prompt,
236       const DoubleSetting &Setting,
237       const int nChars) override;
238    wxSlider * TieSlider(
239       const TranslatableString & Prompt,
240       const IntSetting &Setting,
241       const int max,
242       const int min = 0) override;
243    wxSpinCtrl * TieSpinCtrl(
244       const TranslatableString &Prompt,
245       const IntSetting &Setting,
246       const int max,
247       const int min) override;
248 };
249 
ShuttleGuiGetDefinition(wxWindow * pParent,CommandMessageTarget & target)250 ShuttleGuiGetDefinition::ShuttleGuiGetDefinition(
251    wxWindow * pParent,CommandMessageTarget & target )
252 : ShuttleGui( pParent, eIsGettingMetadata ),
253   CommandMessageTargetDecorator( target )
254 {
255 
256 }
~ShuttleGuiGetDefinition(void)257 ShuttleGuiGetDefinition::~ShuttleGuiGetDefinition(void)
258 {
259 }
260 
TieCheckBox(const TranslatableString & Prompt,const BoolSetting & Setting)261 wxCheckBox * ShuttleGuiGetDefinition::TieCheckBox(
262    const TranslatableString &Prompt,
263    const BoolSetting &Setting)
264 {
265    StartStruct();
266    AddItem( Setting.GetPath(), "id" );
267    AddItem( Prompt.Translation(), "prompt" );
268    AddItem( "bool", "type" );
269    AddBool( Setting.GetDefault(), "default"  );
270    EndStruct();
271    return ShuttleGui::TieCheckBox( Prompt, Setting );
272 }
273 
TieCheckBoxOnRight(const TranslatableString & Prompt,const BoolSetting & Setting)274 wxCheckBox * ShuttleGuiGetDefinition::TieCheckBoxOnRight(
275    const TranslatableString &Prompt,
276    const BoolSetting &Setting)
277 {
278    StartStruct();
279    AddItem( Setting.GetPath(), "id" );
280    AddItem( Prompt.Translation(), "prompt" );
281    AddItem( "bool", "type" );
282    AddBool( Setting.GetDefault(), "default"  );
283    EndStruct();
284    return ShuttleGui::TieCheckBoxOnRight( Prompt, Setting );
285 }
286 
TieChoice(const TranslatableString & Prompt,const ChoiceSetting & choiceSetting)287 wxChoice * ShuttleGuiGetDefinition::TieChoice(
288    const TranslatableString &Prompt,
289    const ChoiceSetting &choiceSetting  )
290 {
291    StartStruct();
292    AddItem( choiceSetting.Key(), "id" );
293    AddItem( Prompt.Translation(), "prompt" );
294    AddItem( "enum", "type" );
295    AddItem( choiceSetting.Default().Internal(), "default"  );
296    StartField( "enum" );
297    StartArray();
298    for ( const auto &choice : choiceSetting.GetSymbols().GetInternals() )
299       AddItem( choice );
300    EndArray();
301    EndField();
302    EndStruct();
303    return ShuttleGui::TieChoice( Prompt, choiceSetting );
304 }
305 
TieNumberAsChoice(const TranslatableString & Prompt,const IntSetting & Setting,const TranslatableStrings & Choices,const std::vector<int> * pInternalChoices,int iNoMatchSelector)306 wxChoice * ShuttleGuiGetDefinition::TieNumberAsChoice(
307    const TranslatableString &Prompt,
308    const IntSetting &Setting,
309    const TranslatableStrings & Choices,
310    const std::vector<int> * pInternalChoices, int iNoMatchSelector)
311 {
312    // Come here for controls that present non-exhaustive choices among some
313    //  numbers, with an associated control that allows arbitrary entry of an
314    // "Other..."
315    StartStruct();
316    AddItem( Setting.GetPath(), "id" );
317    AddItem( Prompt.Translation(), "prompt" );
318    AddItem( "number", "type" ); // not "enum" !
319    AddItem( Setting.GetDefault(), "default"  );
320    EndStruct();
321    return ShuttleGui::TieNumberAsChoice(
322       Prompt, Setting, Choices, pInternalChoices, iNoMatchSelector );
323 }
324 
TieTextBox(const TranslatableString & Prompt,const StringSetting & Setting,const int nChars)325 wxTextCtrl * ShuttleGuiGetDefinition::TieTextBox(
326    const TranslatableString &Prompt,
327    const StringSetting &Setting,
328    const int nChars)
329 {
330    StartStruct();
331    AddItem( Setting.GetPath(), "id" );
332    AddItem( Prompt.Translation(), "prompt" );
333    AddItem( "string", "type" );
334    AddItem( Setting.GetDefault(), "default"  );
335    EndStruct();
336    return ShuttleGui::TieTextBox( Prompt, Setting, nChars );
337 }
338 
TieIntegerTextBox(const TranslatableString & Prompt,const IntSetting & Setting,const int nChars)339 wxTextCtrl * ShuttleGuiGetDefinition::TieIntegerTextBox(
340    const TranslatableString & Prompt,
341    const IntSetting &Setting,
342    const int nChars)
343 {
344    StartStruct();
345    AddItem( Setting.GetPath(), "id" );
346    AddItem( Prompt.Translation(), "prompt" );
347    AddItem( "number", "type" );
348    AddItem( Setting.GetDefault(), "default"  );
349    EndStruct();
350    return ShuttleGui::TieIntegerTextBox( Prompt, Setting, nChars );
351 }
352 
TieNumericTextBox(const TranslatableString & Prompt,const DoubleSetting & Setting,const int nChars)353 wxTextCtrl * ShuttleGuiGetDefinition::TieNumericTextBox(
354    const TranslatableString & Prompt,
355    const DoubleSetting &Setting,
356    const int nChars)
357 {
358    StartStruct();
359    AddItem( Setting.GetPath(), "id" );
360    AddItem( Prompt.Translation(), "prompt" );
361    AddItem( "number", "type" );
362    AddItem( Setting.GetDefault(), "default"  );
363    EndStruct();
364    return ShuttleGui::TieNumericTextBox( Prompt, Setting, nChars );
365 }
366 
TieSlider(const TranslatableString & Prompt,const IntSetting & Setting,const int max,const int min)367 wxSlider * ShuttleGuiGetDefinition::TieSlider(
368    const TranslatableString & Prompt,
369    const IntSetting &Setting,
370    const int max,
371    const int min)
372 {
373    StartStruct();
374    AddItem( Setting.GetPath(), "id" );
375    AddItem( Prompt.Translation(), "prompt" );
376    AddItem( "number", "type" );
377    AddItem( Setting.GetDefault(), "default"  );
378    EndStruct();
379    return ShuttleGui::TieSlider( Prompt, Setting, max, min );
380 }
381 
TieSpinCtrl(const TranslatableString & Prompt,const IntSetting & Setting,const int max,const int min)382 wxSpinCtrl * ShuttleGuiGetDefinition::TieSpinCtrl(
383    const TranslatableString &Prompt,
384    const IntSetting &Setting,
385    const int max,
386    const int min)
387 {
388    StartStruct();
389    AddItem( Setting.GetPath(), "id" );
390    AddItem( Prompt.Translation(), "prompt" );
391    AddItem( "number", "type" );
392    AddItem( Setting.GetDefault(), "default"  );
393    EndStruct();
394    return ShuttleGui::TieSpinCtrl( Prompt, Setting, max, min );
395 }
396 
397 }
398 
SendPreferences(const CommandContext & context)399 bool GetInfoCommand::SendPreferences(const CommandContext &context)
400 {
401    context.StartArray();
402    auto pWin = &GetProjectFrame( context.project );
403    GlobalPrefsDialog dialog( pWin, &context.project );
404    // wxCommandEvent Evt;
405    //dialog.Show();
406    ShuttleGuiGetDefinition S(pWin, *((context.pOutput)->mStatusTarget) );
407     dialog.ShuttleAll( S );
408    context.EndArray();
409    return true;
410 }
411 
412 /**
413  Send the list of commands.
414  */
SendCommands(const CommandContext & context,int flags)415 bool GetInfoCommand::SendCommands(const CommandContext &context, int flags )
416 {
417    context.StartArray();
418    PluginManager & pm = PluginManager::Get();
419    EffectManager & em = EffectManager::Get();
420    {
421       for (auto &plug
422            : pm.PluginsOfType(PluginTypeEffect | PluginTypeAudacityCommand)) {
423          auto command = em.GetCommandIdentifier(plug.GetID());
424          if (!command.empty()){
425             em.GetCommandDefinition( plug.GetID(), context, flags );
426          }
427       }
428    }
429    context.EndArray();
430    return true;
431 }
432 
SendBoxes(const CommandContext & context)433 bool GetInfoCommand::SendBoxes(const CommandContext &context)
434 {
435    //context.Status("Boxes");
436    auto pWin = &GetProjectFrame( context.project );
437 
438    context.StartArray();
439    wxRect R = pWin->GetScreenRect();
440 
441    //R.SetPosition( wxPoint(0,0) );
442 
443    //wxString Name = pWin->GetName();
444    context.StartStruct();
445    context.AddItem( 0, "depth" );
446    context.AddItem( "Audacity Window", "name" );
447    context.StartField( "box" );
448    context.StartArray( );
449    context.AddItem( R.GetLeft() );
450    context.AddItem( R.GetTop() );
451    context.AddItem( R.GetRight() );
452    context.AddItem( R.GetBottom() );
453    context.EndArray( );
454    context.EndField();
455    context.EndStruct( );
456 
457    ExploreAdornments( context, pWin->GetPosition()+wxSize( 6,-1), pWin, pWin->GetId(), 1 );
458    ExploreWindows( context, pWin->GetPosition()+wxSize( 6,-1), pWin, pWin->GetId(), 1 );
459    context.EndArray( );
460    return true;
461 }
462 
SendTracks(const CommandContext & context)463 bool GetInfoCommand::SendTracks(const CommandContext & context)
464 {
465    auto &tracks = TrackList::Get( context.project );
466    context.StartArray();
467    for (auto trk : tracks.Leaders())
468    {
469       auto &trackFocus = TrackFocus::Get( context.project );
470       Track * fTrack = trackFocus.Get();
471 
472       context.StartStruct();
473       context.AddItem( trk->GetName(), "name" );
474       context.AddBool( (trk == fTrack), "focused");
475       context.AddBool( trk->GetSelected(), "selected" );
476       //JKC: Possibly add later...
477       //context.AddItem( TrackView::Get( *trk ).GetHeight(), "height" );
478       trk->TypeSwitch( [&] (const WaveTrack* t ) {
479          float vzmin, vzmax;
480          t->GetDisplayBounds(&vzmin, &vzmax);
481          context.AddItem( "wave", "kind" );
482          context.AddItem( t->GetStartTime(), "start" );
483          context.AddItem( t->GetEndTime(), "end" );
484          context.AddItem( t->GetPan() , "pan");
485          context.AddItem( t->GetGain() , "gain");
486          context.AddItem( TrackList::Channels(t).size(), "channels");
487          context.AddBool( t->GetSolo(), "solo" );
488          context.AddBool( t->GetMute(), "mute");
489          context.AddItem( vzmin, "VZoomMin");
490          context.AddItem( vzmax, "VZoomMax");
491       },
492 #if defined(USE_MIDI)
493       [&](const NoteTrack *) {
494          context.AddItem( "note", "kind" );
495       },
496 #endif
497       [&](const LabelTrack *) {
498          context.AddItem( "label", "kind" );
499       },
500       [&](const TimeTrack *) {
501          context.AddItem( "time", "kind" );
502       }
503       );
504       context.EndStruct();
505    }
506    context.EndArray();
507    return true;
508 }
509 
SendClips(const CommandContext & context)510 bool GetInfoCommand::SendClips(const CommandContext &context)
511 {
512    auto &tracks = TrackList::Get( context.project );
513    int i=0;
514    context.StartArray();
515    for (auto t : tracks.Leaders()) {
516       t->TypeSwitch([&](WaveTrack *waveTrack) {
517          WaveClipPointers ptrs(waveTrack->SortedClipArray());
518          for (WaveClip * pClip : ptrs) {
519             context.StartStruct();
520             context.AddItem((double)i, "track");
521             context.AddItem(pClip->GetPlayStartTime(), "start");
522             context.AddItem(pClip->GetPlayEndTime(), "end");
523             context.AddItem(pClip->GetColourIndex(), "color");
524             context.EndStruct();
525          }
526       });
527       // Per track numbering counts all tracks
528       i++;
529    }
530    context.EndArray();
531 
532    return true;
533 }
534 
SendEnvelopes(const CommandContext & context)535 bool GetInfoCommand::SendEnvelopes(const CommandContext &context)
536 {
537    auto &tracks = TrackList::Get( context.project );
538    int i=0;
539    int j=0;
540    context.StartArray();
541    for (auto t : tracks.Leaders()) {
542       t->TypeSwitch([&](WaveTrack *waveTrack) {
543          WaveClipPointers ptrs(waveTrack->SortedClipArray());
544          j = 0;
545          for (WaveClip * pClip : ptrs) {
546             context.StartStruct();
547             context.AddItem((double)i, "track");
548             context.AddItem((double)j, "clip");
549             context.AddItem(pClip->GetPlayStartTime(), "start");
550             Envelope * pEnv = pClip->GetEnvelope();
551             context.StartField("points");
552             context.StartArray();
553             double offset = pEnv->GetOffset();
554             for (size_t k = 0; k < pEnv->GetNumberOfPoints(); k++)
555             {
556                context.StartStruct();
557                context.AddItem((*pEnv)[k].GetT() + offset, "t");
558                context.AddItem((*pEnv)[k].GetVal(), "y");
559                context.EndStruct();
560             }
561             context.EndArray();
562             context.EndField();
563             context.AddItem(pClip->GetPlayEndTime(), "end");
564             context.EndStruct();
565             j++;
566          }
567       });
568       // Per track numbering counts all tracks
569       i++;
570    }
571    context.EndArray();
572 
573    return true;
574 }
575 
576 
SendLabels(const CommandContext & context)577 bool GetInfoCommand::SendLabels(const CommandContext &context)
578 {
579    auto &tracks = TrackList::Get( context.project );
580    int i=0;
581    context.StartArray();
582    for (auto t : tracks.Leaders()) {
583       t->TypeSwitch( [&](LabelTrack *labelTrack) {
584 #ifdef VERBOSE_LABELS_FORMATTING
585          for (int nn = 0; nn< (int)labelTrack->mLabels.size(); nn++) {
586             const auto &label = labelTrack->mLabels[nn];
587             context.StartStruct();
588             context.AddItem( (double)i, "track" );
589             context.AddItem( label.getT0(), "start" );
590             context.AddItem( label.getT1(), "end" );
591             context.AddItem( label.title, "text" );
592             context.EndStruct();
593          }
594 #else
595          context.StartArray();
596          context.AddItem( (double)i ); // Track number.
597          context.StartArray();
598          for ( const auto &label : labelTrack->GetLabels() ) {
599             context.StartArray();
600             context.AddItem( label.getT0() ); // start
601             context.AddItem( label.getT1() ); // end
602             context.AddItem( label.title ); //text.
603             context.EndArray();
604          }
605          context.EndArray();
606          context.EndArray();
607 #endif
608       } );
609       // Per track numbering counts all tracks
610       i++;
611    }
612    context.EndArray();
613 
614    return true;
615 }
616 
617 /*******************************************************************
618 The various Explore functions are called from the Send functions,
619 and may be recursive.  'Send' is the top level.
620 *******************************************************************/
621 
ExploreMenu(const CommandContext & context,wxMenu * pMenu,int Id,int depth)622 void GetInfoCommand::ExploreMenu( const CommandContext &context, wxMenu * pMenu, int Id, int depth ){
623    static_cast<void>(Id);//compiler food.
624    if( !pMenu )
625       return;
626 
627    auto &commandManager = CommandManager::Get( context.project );
628 
629    wxMenuItemList list = pMenu->GetMenuItems();
630    size_t lcnt = list.size();
631    wxMenuItem * item;
632    wxString Label;
633    wxString Accel;
634    CommandID Name;
635 
636    for (size_t lndx = 0; lndx < lcnt; lndx++) {
637       item = list.Item(lndx)->GetData();
638       Label = item->GetItemLabelText();
639       Name = commandManager.GetNameFromNumericID( item->GetId() );
640       Accel = item->GetItemLabel();
641       if( Accel.Contains("\t") )
642          Accel = Accel.AfterLast('\t');
643       else
644          Accel = "";
645       if( item->IsSeparator() )
646          Label = "----";
647       int flags = 0;
648       if (item->IsSubMenu())
649          flags +=1;
650       if (item->IsCheck() && item->IsChecked())
651          flags +=2;
652 
653       context.StartStruct();
654       context.AddItem( depth, "depth" );
655       context.AddItem( flags, "flags" );
656       context.AddItem( Label, "label" );
657       context.AddItem( Accel, "accel" );
658       if( !Name.empty() )
659          // using GET to expose CommandID in results of GetInfoCommand...
660          // PRL asks, is that all right?
661          context.AddItem( Name.GET(), "id" );// It is called Scripting ID outside Audacity.
662       context.EndStruct();
663 
664       if (item->IsSubMenu()) {
665          pMenu = item->GetSubMenu();
666          ExploreMenu( context, pMenu, item->GetId(), depth+1 );
667       }
668    }
669 }
670 
ExploreAdornments(const CommandContext & context,wxPoint WXUNUSED (P),wxWindow * pWin,int WXUNUSED (Id),int depth)671 void GetInfoCommand::ExploreAdornments( const CommandContext &context,
672    wxPoint WXUNUSED(P), wxWindow * pWin, int WXUNUSED(Id), int depth )
673 {
674    // Dang! wxMenuBar returns bogus screen rect.
675    // We're going to have to fake it instead.
676    //wxMenuBar * pBar = context.GetProject()->GetMenuBar();
677    //wxRect R = pBar->GetScreenRect();
678    //R.SetPosition( R.GetPosition() - P );
679 
680    wxRect R1 = pWin->GetScreenRect();
681    wxSize s = pWin->GetWindowBorderSize();
682    wxRect R( 2,32, R1.GetWidth() - s.GetWidth() * 2 -16, 22 );
683 
684    context.StartStruct();
685    context.AddItem( depth, "depth" );
686    context.AddItem( "MenuBar", "label" );
687    context.StartField( "box" );
688    context.StartArray();
689    context.AddItem( R.GetLeft() );
690    context.AddItem( R.GetTop() );
691    context.AddItem( R.GetRight() );
692    context.AddItem( R.GetBottom() );
693    context.EndArray();
694    context.EndField();
695    context.EndStruct();
696 }
697 
ExploreTrackPanel(const CommandContext & context,wxPoint P,int depth)698 void GetInfoCommand::ExploreTrackPanel( const CommandContext &context,
699    wxPoint P, int depth )
700 {
701    AudacityProject * pProj = &context.project;
702    auto &tp = TrackPanel::Get( *pProj );
703    wxRect panelRect{ {}, tp.GetSize() };
704    for ( auto t : TrackList::Get( *pProj ).Any() ) {
705       auto rulers = tp.FindRulerRects(t);
706       for (auto &R : rulers) {
707          if (!R.Intersects(panelRect))
708             continue;
709          R.SetPosition( R.GetPosition() + P );
710          context.StartStruct();
711          context.AddItem( depth, "depth" );
712          context.AddItem( "VRuler", "label" );
713          context.StartField("box");
714          context.StartArray();
715          context.AddItem( R.GetLeft() );
716          context.AddItem( R.GetTop() );
717          context.AddItem( R.GetRight() );
718          context.AddItem( R.GetBottom() );
719          context.EndArray();
720          context.EndField();
721          context.EndStruct();
722       }
723    }
724 }
725 
726 
ExploreWindows(const CommandContext & context,wxPoint P,wxWindow * pWin,int Id,int depth)727 void GetInfoCommand::ExploreWindows( const CommandContext &context,
728    wxPoint P, wxWindow * pWin, int Id, int depth )
729 {
730    static_cast<void>(Id);//Compiler food.
731 
732    if( pWin->GetName() == "Track Panel" )
733    {
734       wxRect R = pWin->GetScreenRect();
735       ExploreTrackPanel(  context, R.GetPosition()-P, depth );
736       return;
737    }
738    wxWindowList list = pWin->GetChildren();
739    size_t lcnt = list.size();
740 
741    for (size_t lndx = 0; lndx < lcnt; lndx++) {
742       wxWindow * item = list[lndx];
743       if( !item->IsShown() )
744          continue;
745       wxRect R = item->GetScreenRect();
746       R.SetPosition( R.GetPosition() - P );
747       wxString Name = item->GetName();
748       // Ignore staticLine and StaticBitmap.
749       if( Name.StartsWith( "static" ) )
750          continue;
751       // Ignore anonymous panels.
752       if( Name == "panel"  )
753          continue;
754       if( Name.empty() )
755          Name = wxString("*") + item->GetToolTipText();
756 
757       context.StartStruct();
758       context.AddItem( depth, "depth" );
759       context.AddItem( Name, "label" );
760       context.AddItem( item->GetId(), "id" );
761       context.StartField( "box" );
762       context.StartArray();
763       context.AddItem( R.GetLeft() );
764       context.AddItem( R.GetTop() );
765       context.AddItem( R.GetRight() );
766       context.AddItem( R.GetBottom() );
767       context.EndArray();
768       context.EndField();
769       context.EndStruct();
770 
771       ExploreWindows( context, P, item, item->GetId(), depth+1 );
772    }
773 }
774 
775