1 /**********************************************************************
2 
3   Audacity: A Digital Audio Editor
4 
5   EditToolBar.cpp
6 
7   Dominic Mazzoni
8   Shane T. Mueller
9   Leland Lucius
10 
11   See EditToolBar.h for details
12 
13 *******************************************************************//*!
14 
15 \class EditToolBar
16 \brief A ToolBar that has the edit buttons on it.
17 
18   This class, which is a child of Toolbar, creates the
19   window containing interfaces to commonly-used edit
20   functions that are otherwise only available through
21   menus. The window can be embedded within a normal project
22   window, or within a ToolBarFrame.
23 
24   All of the controls in this window were custom-written for
25   Audacity - they are not native controls on any platform -
26   however, it is intended that the images could be easily
27   replaced to allow "skinning" or just customization to
28   match the look and feel of each platform.
29 
30 *//*******************************************************************/
31 
32 
33 
34 #include "EditToolBar.h"
35 
36 // For compilers that support precompilation, includes "wx/wx.h".
37 #include <wx/wxprec.h>
38 
39 #include <wx/setup.h> // for wxUSE_* macros
40 
41 #ifndef WX_PRECOMP
42 #include <wx/app.h>
43 #include <wx/event.h>
44 #include <wx/image.h>
45 #include <wx/intl.h>
46 #include <wx/sizer.h>
47 #include <wx/tooltip.h>
48 #endif
49 
50 #include "AllThemeResources.h"
51 #include "../BatchCommands.h"
52 #include "ImageManipulation.h"
53 #include "../Menus.h"
54 #include "Prefs.h"
55 #include "Project.h"
56 #include "../UndoManager.h"
57 #include "../widgets/AButton.h"
58 
59 #include "../commands/CommandContext.h"
60 #include "../commands/CommandManager.h"
61 
62 IMPLEMENT_CLASS(EditToolBar, ToolBar);
63 
64 const int BUTTON_WIDTH = 27;
65 const int SEPARATOR_WIDTH = 14;
66 
67 ////////////////////////////////////////////////////////////
68 /// Methods for EditToolBar
69 ////////////////////////////////////////////////////////////
70 
BEGIN_EVENT_TABLE(EditToolBar,ToolBar)71 BEGIN_EVENT_TABLE( EditToolBar, ToolBar )
72    EVT_COMMAND_RANGE( ETBCutID+first_ETB_ID,
73                       ETBCutID+first_ETB_ID + ETBNumButtons - 1,
74                       wxEVT_COMMAND_BUTTON_CLICKED,
75                       EditToolBar::OnButton )
76 END_EVENT_TABLE()
77 
78 //Standard constructor
79 EditToolBar::EditToolBar( AudacityProject &project )
80 : ToolBar(project, EditBarID, XO("Edit"), wxT("Edit"))
81 {
82 }
83 
~EditToolBar()84 EditToolBar::~EditToolBar()
85 {
86 }
87 
Create(wxWindow * parent)88 void EditToolBar::Create(wxWindow * parent)
89 {
90    ToolBar::Create(parent);
91    UpdatePrefs();
92 }
93 
AddSeparator()94 void EditToolBar::AddSeparator()
95 {
96    AddSpacer();
97 }
98 
99 /// This is a convenience function that allows for button creation in
100 /// MakeButtons() with fewer arguments
101 /// Very similar to code in ControlToolBar...
AddButton(EditToolBar * pBar,teBmps eEnabledUp,teBmps eEnabledDown,teBmps eDisabled,int id,const TranslatableString & label,bool toggle)102 AButton *EditToolBar::AddButton(
103    EditToolBar *pBar,
104    teBmps eEnabledUp, teBmps eEnabledDown, teBmps eDisabled,
105    int id,
106    const TranslatableString &label,
107    bool toggle)
108 {
109    AButton *&r = pBar->mButtons[id];
110 
111    r = ToolBar::MakeButton(pBar,
112       bmpRecoloredUpSmall, bmpRecoloredDownSmall, bmpRecoloredUpHiliteSmall, bmpRecoloredHiliteSmall,
113       eEnabledUp, eEnabledDown, eDisabled,
114       wxWindowID(id+first_ETB_ID),
115       wxDefaultPosition,
116       toggle,
117       theTheme.ImageSize( bmpRecoloredUpSmall ));
118 
119    r->SetLabel(label);
120 // JKC: Unlike ControlToolBar, does not have a focus rect.  Shouldn't it?
121 // r->SetFocusRect( r->GetRect().Deflate( 4, 4 ) );
122 
123    pBar->Add( r, 0, wxALIGN_CENTER );
124 
125    return r;
126 }
127 
Populate()128 void EditToolBar::Populate()
129 {
130    SetBackgroundColour( theTheme.Colour( clrMedium  ) );
131    MakeButtonBackgroundsSmall();
132 
133    /* Buttons */
134    // Tooltips slightly more verbose than the menu entries are.
135    AddButton(this, bmpCut, bmpCut, bmpCutDisabled, ETBCutID,
136       XO("Cut selection"));
137    AddButton(this, bmpCopy, bmpCopy, bmpCopyDisabled, ETBCopyID,
138       XO("Copy selection"));
139    AddButton(this, bmpPaste, bmpPaste, bmpPasteDisabled, ETBPasteID,
140       XO("Paste"));
141    AddButton(this, bmpTrim, bmpTrim, bmpTrimDisabled, ETBTrimID,
142       XO("Trim audio outside selection"));
143    AddButton(this, bmpSilence, bmpSilence, bmpSilenceDisabled, ETBSilenceID,
144       XO("Silence audio selection"));
145 
146    AddSeparator();
147 
148    AddButton(this, bmpUndo, bmpUndo, bmpUndoDisabled, ETBUndoID,
149       XO("Undo"));
150    AddButton(this, bmpRedo, bmpRedo, bmpRedoDisabled, ETBRedoID,
151       XO("Redo"));
152 
153    AddSeparator();
154 
155 #ifdef OPTION_SYNC_LOCK_BUTTON
156    AddButton(this, bmpSyncLockTracksUp, bmpSyncLockTracksDown, bmpSyncLockTracksUp, ETBSyncLockID,
157                XO("Sync-Lock Tracks"), true);
158 
159    AddSeparator();
160 #endif
161 
162    // Tooltips match menu entries.
163    // We previously had longer tooltips which were not more clear.
164    AddButton(this, bmpZoomIn, bmpZoomIn, bmpZoomInDisabled, ETBZoomInID,
165       XO("Zoom In"));
166    AddButton(this, bmpZoomOut, bmpZoomOut, bmpZoomOutDisabled, ETBZoomOutID,
167       XO("Zoom Out"));
168    AddButton(this, bmpZoomSel, bmpZoomSel, bmpZoomSelDisabled, ETBZoomSelID,
169       XO("Zoom to Selection"));
170    AddButton(this, bmpZoomFit, bmpZoomFit, bmpZoomFitDisabled, ETBZoomFitID,
171       XO("Fit to Width"));
172 
173 #ifdef EXPERIMENTAL_ZOOM_TOGGLE_BUTTON
174    AddButton(this, bmpZoomToggle, bmpZoomToggle, bmpZoomToggleDisabled, ETBZoomToggleID,
175       XO("Zoom Toggle"));
176 #endif
177 
178 
179 
180    mButtons[ETBZoomInID]->SetEnabled(false);
181    mButtons[ETBZoomOutID]->SetEnabled(false);
182 #ifdef EXPERIMENTAL_ZOOM_TOGGLE_BUTTON
183    mButtons[ETBZoomToggleID]->SetEnabled(false);
184 #endif
185 
186    mButtons[ETBZoomSelID]->SetEnabled(false);
187    mButtons[ETBZoomFitID]->SetEnabled(false);
188    mButtons[ETBPasteID]->SetEnabled(false);
189 
190 #ifdef OPTION_SYNC_LOCK_BUTTON
191    mButtons[ETBSyncLockID]->PushDown();
192 #endif
193 
194 #if defined(EXPERIMENTAL_EFFECTS_RACK)
195    AddSeparator();
196    AddButton(this, bmpEditEffects, bmpEditEffects, bmpEditEffects, ETBEffectsID,
197       XO("Show Effects Rack"), true);
198 #endif
199 
200    RegenerateTooltips();
201 }
202 
UpdatePrefs()203 void EditToolBar::UpdatePrefs()
204 {
205    RegenerateTooltips();
206 
207    // Set label to pull in language change
208    SetLabel(XO("Edit"));
209 
210    // Give base class a chance
211    ToolBar::UpdatePrefs();
212 }
213 
RegenerateTooltips()214 void EditToolBar::RegenerateTooltips()
215 {
216    ForAllButtons( ETBActTooltips );
217 }
218 
EnableDisableButtons()219 void EditToolBar::EnableDisableButtons()
220 {
221    ForAllButtons( ETBActEnableDisable );
222 }
223 
224 
225 static const struct Entry {
226    int tool;
227    CommandID commandName;
228    TranslatableString untranslatedLabel;
229 } EditToolbarButtonList[] = {
230    { ETBCutID,      wxT("Cut"),         XO("Cut")  },
231    { ETBCopyID,     wxT("Copy"),        XO("Copy")  },
232    { ETBPasteID,    wxT("Paste"),       XO("Paste")  },
233    { ETBTrimID,     wxT("Trim"),        XO("Trim audio outside selection")  },
234    { ETBSilenceID,  wxT("Silence"),     XO("Silence audio selection")  },
235    { ETBUndoID,     wxT("Undo"),        XO("Undo")  },
236    { ETBRedoID,     wxT("Redo"),        XO("Redo")  },
237 
238 #ifdef OPTION_SYNC_LOCK_BUTTON
239    { ETBSyncLockID, wxT("SyncLock"),    XO("Sync-Lock Tracks")  },
240 #endif
241 
242    { ETBZoomInID,   wxT("ZoomIn"),      XO("Zoom In")  },
243    { ETBZoomOutID,  wxT("ZoomOut"),     XO("Zoom Out")  },
244 #ifdef EXPERIMENTAL_ZOOM_TOGGLE_BUTTON
245    { ETBZoomToggleID,   wxT("ZoomToggle"),      XO("Zoom Toggle")  },
246 #endif
247    { ETBZoomSelID,  wxT("ZoomSel"),     XO("Fit selection to width")  },
248    { ETBZoomFitID,  wxT("FitInWindow"), XO("Fit project to width")  },
249 
250 #if defined(EXPERIMENTAL_EFFECTS_RACK)
251    { ETBEffectsID,  wxT("ShowEffectsRack"), XO("Open Effects Rack")  },
252 #endif
253 };
254 
255 
ForAllButtons(int Action)256 void EditToolBar::ForAllButtons(int Action)
257 {
258    AudacityProject *p;
259    CommandManager* cm = nullptr;
260 
261    if( Action & ETBActEnableDisable ){
262       p = &mProject;
263       cm = &CommandManager::Get( *p );
264 #ifdef OPTION_SYNC_LOCK_BUTTON
265       bool bSyncLockTracks;
266       gPrefs->Read(wxT("/GUI/SyncLockTracks"), &bSyncLockTracks, false);
267 
268       if (bSyncLockTracks)
269          mButtons[ETBSyncLockID]->PushDown();
270       else
271          mButtons[ETBSyncLockID]->PopUp();
272 #endif
273    }
274 
275 
276    for (const auto &entry : EditToolbarButtonList) {
277 #if wxUSE_TOOLTIPS
278       if( Action & ETBActTooltips ){
279          ComponentInterfaceSymbol command{
280             entry.commandName, entry.untranslatedLabel };
281          ToolBar::SetButtonToolTip( mProject,
282             *mButtons[entry.tool], &command, 1u );
283       }
284 #endif
285       if (cm) {
286          mButtons[entry.tool]->SetEnabled(cm->GetEnabled(entry.commandName));
287       }
288    }
289 }
290 
OnButton(wxCommandEvent & event)291 void EditToolBar::OnButton(wxCommandEvent &event)
292 {
293    int id = event.GetId()-first_ETB_ID;
294    // Be sure the pop-up happens even if there are exceptions, except for buttons which toggle.
295    auto cleanup = finally( [&] { mButtons[id]->InteractionOver();});
296 
297    AudacityProject *p = &mProject;
298    auto &cm = CommandManager::Get( *p );
299 
300    auto flags = MenuManager::Get(*p).GetUpdateFlags();
301    const CommandContext context( *p );
302    MacroCommands::HandleTextualCommand( cm,
303       EditToolbarButtonList[id].commandName, context, flags, false);
304 
305 #if defined(__WXMAC__)
306    // Bug 2402
307    // LLL: It seems that on the Mac the IDLE events are processed
308    //      differently than on Windows/GTK and the AdornedRulerPanel's
309    //      OnPaint() method gets called sooner that expected. This is
310    //      evident when zooming from this toolbar only. When zooming from
311    //      the Menu or from keyboard ommand, the zooming works correctly.
312    wxTheApp->ProcessIdle();
313 #endif
314 }
315 
316 static RegisteredToolbarFactory factory{ EditBarID,
__anonc8995de80202( )317    []( AudacityProject &project ){
318       return ToolBar::Holder{ safenew EditToolBar{ project } }; }
319 };
320 
321 #include "ToolManager.h"
322 
323 namespace {
324 AttachedToolBarMenuItem sAttachment{
325    /* i18n-hint: Clicking this menu item shows the toolbar for editing */
326    EditBarID, wxT("ShowEditTB"), XXO("&Edit Toolbar")
327 };
328 }
329 
330