Audacity  2.2.2
ToolDock.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  ToolBar.cpp
6 
7  Dominic Mazzoni
8  Shane T. Mueller
9  Leland Lucius
10 
11 *******************************************************************//*******************************************************************//**********************************************************************/
23 
24 #include "../Audacity.h"
25 #include <wx/tokenzr.h>
26 
27 // For compilers that support precompilation, includes "wx/wx.h".
28 #include <wx/wxprec.h>
29 
30 #ifndef WX_PRECOMP
31 #include <wx/defs.h>
32 #include <wx/event.h>
33 #include <wx/gdicmn.h>
34 #include <wx/intl.h>
35 #include <wx/panel.h>
36 #include <wx/settings.h>
37 #include <wx/window.h>
38 #endif /* */
39 
40 #include "ToolManager.h"
41 #include "ToolDock.h"
42 
43 #include <algorithm>
44 
45 #include "../AColor.h"
46 #include "../AllThemeResources.h"
47 #include "../ImageManipulation.h"
48 #include "../Prefs.h"
49 #include "../Project.h"
50 #include "../Theme.h"
51 #include "../widgets/AButton.h"
52 #include "../widgets/Grabber.h"
53 
56 
58  -> Iterator
59 {
60  auto This = const_cast<ToolBarConfiguration*>(this);
61  return std::find_if(This->begin(), This->end(),
62  [=](const Place &place){
63  return place.pTree->pBar == bar;
64  });
65 }
66 
68  -> std::pair<Forest*, Forest::iterator>
69 {
70  auto findTree = [=](Forest &forest){
71  return std::find_if(forest.begin(), forest.end(),
72  [=](const Tree &tree){ return tree.pBar == bar; });
73  };
74 
75  auto iter1 = findTree(mForest);
76  if (iter1 != mForest.end())
77  return { &mForest, iter1 };
78 
79  Forest::iterator result;
80  auto iter = std::find_if(begin(), end(),
81  [&](const Place &place){
82  auto &children = place.pTree->children;
83  return (result = findTree(children)) != children.end();
84  }
85  );
86  if (iter != end())
87  return { &iter->pTree->children, result };
88 
89  return { nullptr, Forest::iterator{} };
90 }
91 
92 auto ToolBarConfiguration::Find(const ToolBar *bar) const -> Position
93 {
94  auto iter = FindPlace(bar);
95  if (iter == end())
96  return UnspecifiedPosition;
97  else
98  return iter->position;
99 }
100 
102 {
103  if (position == UnspecifiedPosition) {
104  // Add at the "end" of the layout
105  // bottommost and rightmost
106  Forest *pForest = &mForest;
107  while (!pForest->empty())
108  pForest = &pForest->back().children;
109  pForest->push_back( Tree {} );
110  pForest->back().pBar = bar;
111  }
112  else {
113  // Insert at what depth?
114  auto pForest = &mForest;
115  if (position.rightOf) {
116  const auto parent = FindPlace(position.rightOf);
117  if (parent != end())
118  // Insert among children of some node
119  pForest = &parent->pTree->children;
120  }
121  else {
122  // Insert a new root in the top forest
123  }
124 
125  // Insert at what breadth?
126  const auto begin = pForest->begin();
127  auto iter = begin;
128  const auto end = pForest->end();
129  bool adopt = false;
130 
131  if (position.below) {
132  iter = std::find_if(begin, end,
133  [=](const Tree &tree){ return tree.pBar == position.below; }
134  );
135  if (iter != end) {
136  ++iter;
137  if (iter != end)
138  adopt = true;
139  }
140  else
141  // Not found, default to topmost
142  iter = begin;
143  }
144  else
145  // No previous sibling specified, so insert as first
146  adopt = (iter != end);
147 
148  // Insert as a leaf, or as an internal node?
149  if (adopt && position.adopt) {
150  // Existing child of parent become its grandchild
151 
152  // TODO: is it ever correct to adopt more than one, depending on
153  // heights? Could an inserted tall bar adopt two short ones?
154 
155  // Make NEW node
156  Tree tree;
157  tree.pBar = bar;
158 
159  // Do adoption
160  tree.children.push_back(Tree{});
161  auto &child = tree.children.back();
162  child.pBar = iter->pBar;
163  child.children.swap(iter->children);
164 
165  // Put the node in the tree
166  (*iter).swap(tree);
167  }
168  else
169  // Insert as a leaf
170  pForest->insert(iter, Tree {})->pBar = bar;
171  }
172 }
173 
175  (ToolBar *bar, const std::vector<int> &path)
176 {
177  auto pForest = &mForest;
178  Tree *pTree {};
179 
180  // Guarantee the existence of nodes
181  for (auto ii : path) {
182  Forest::size_type uu = std::max(0, ii);
183  // This may make more than one default-constructed tree, which we
184  // will fill in with some other call to InsertAtPath, or else cleanup
185  // with RemoveNulls
186  pForest->resize(std::max(uu + 1, pForest->size()));
187  pTree = &(*pForest)[uu];
188  pForest = &pTree->children;
189  }
190 
191  if (pTree)
192  pTree->pBar = bar;
193 }
194 
195 void ToolBarConfiguration::Remove(Forest &forest, Forest::iterator iter)
196 {
197  // Reparent all of the children of the deleted node
198  Tree tree;
199  tree.swap(*iter);
200  iter = forest.erase(iter);
201  auto &children = tree.children;
202  auto cIter = children.rbegin(), cEnd = children.rend();
203  while (cIter != cEnd) {
204  iter = forest.insert(iter, Tree{});
205  (*iter).swap(*cIter);
206  ++cIter;
207  }
208 }
209 
211 {
212  auto results = FindPeers(bar);
213  auto pForest = results.first;
214  if (pForest) {
215  // Reparent all of the children of the deleted node
216  auto iter = results.second;
217  wxASSERT(iter->pBar == bar);
218  Remove(*pForest, iter);
219  }
220 }
221 
223 {
224  // Do not assume the bar is absent, though in practice that is always so
225  if (!Contains(bar))
226  Insert(bar);
227 }
228 
230 {
231  // Future: might hide a bar without eliminating it from the configuration
232  Remove(bar);
233 }
234 
236 {
237  auto iter = FindPlace(bar);
238  auto endit = end();
239  if (iter == endit)
240  // not present
241  return true;
242  if (++iter == endit)
243  // Last of all
244  return true;
245  if (bar->GetRect().y != iter->pTree->pBar->GetRect().y)
246  // Next step in preorder traversal is not rightward to a child drawn at
247  // the same height
248  return true;
249  return false;
250 }
251 
253  (ToolBarConfiguration *pConfiguration,
254  Legacy *pLegacy,
255  ToolBar *bar, bool &visible, bool defaultVisible)
256 {
257  bool result = true;
258 
259  // Future: might remember visibility in the configuration, not forgetting
260  // positions of hidden bars.
261  gPrefs->Read( wxT("Show"), &visible, defaultVisible);
262 
263  if (pConfiguration && visible) {
264  int ord;
265  gPrefs->Read( wxT("Order"), &ord, -1 );
266  // Index was written 1-based
267  --ord;
268  if (ord >= ToolBarCount)
269  result = false;
270  else if (ord >= 0)
271  {
272  // Legacy preferences
273  while (pLegacy->bars.size() <= size_t(ord))
274  pLegacy->bars.push_back(nullptr);
275  pLegacy->bars[ord] = bar;
276  }
277  else {
278  wxString strPath;
279  gPrefs->Read( wxT("Path"), &strPath );
280  if (!strPath.empty()) {
281  wxStringTokenizer toker { strPath, wxT(",") };
282  std::vector<int> path;
283  while(toker.HasMoreTokens()) {
284  auto token = toker.GetNextToken();
285  auto ii = wxAtoi(token);
286  path.push_back(ii);
287  }
288  pConfiguration->InsertAtPath(bar, path);
289  }
290  }
291  }
292 
293  return result;
294 }
295 
297 {
298  for (size_t ii = 0; ii < forest.size(); ++ii) {
299  if(forest[ii].pBar == nullptr)
300  Remove(forest, forest.begin() + ii--);
301  }
302 
303  // Now do the same recursively
304  for (auto &tree : forest)
305  RemoveNulls(tree.children);
306 }
307 
309 {
310  // Be sure no nodes contain NULL,
311  // against the case of obsolete preferences, perhaps
313 
314  // Interpret what was saved in old .cfg files under "order"
315  // which specified toolbar configuration simply as a sequence, not a tree
316  ToolBar *prev {};
317  for (auto pBar : legacy.bars) {
318  if (!pBar)
319  continue;
320 
321  Position position{ prev };
322  Insert(pBar, position);
323 
324  prev = pBar;
325  }
326 }
327 
329  (const ToolBarConfiguration *pConfiguration, const ToolBar *bar)
330 {
331  // Assume a path has been set in gPrefs suitable for bar
332  if (pConfiguration) {
333  // Write comma-separated list of numbers specifying position in the tree
334  wxString strPath;
335  const auto cIter = pConfiguration->FindPlace(bar);
336  const auto path = cIter.GetPath();
337  if (!path.empty()) {
338  auto iter = path.begin(), end = path.end();
339  strPath += wxString::Format(wxT("%d"), *iter++);
340  while (iter != end)
341  strPath += wxString::Format(wxT(",%d"), *iter++);
342  }
343  gPrefs->Write(wxT("Path"), strPath);
344 
345  // Remove any legacy configuration info.
346  // Note: this causes Audacity 2.1.2 and earlier to create toolbars
347  // always in default position when reading a .cfg saved by Audacity
348  // 2.1.3 or later
349  gPrefs->DeleteEntry(wxT("Order"));
350  }
351  gPrefs->Write( wxT("Show"), bar->IsVisible() );
352 }
353 
355 
359 
360 //
361 // Custom event
362 //
363 //DEFINE_EVENT_TYPE( EVT_TOOLBAR_FLOAT );
364 
365 BEGIN_EVENT_TABLE( ToolDock, wxPanelWrapper )
366  EVT_GRABBER( wxID_ANY, ToolDock::OnGrabber )
367  EVT_ERASE_BACKGROUND( ToolDock::OnErase )
368  EVT_PAINT( ToolDock::OnPaint )
369  EVT_SIZE( ToolDock::OnSize )
370  EVT_MOUSE_EVENTS( ToolDock::OnMouseEvents )
372 
373 //
374 // Constructor
375 //
376 ToolDock::ToolDock( ToolManager *manager, wxWindow *parent, int dockid ):
377  wxPanelWrapper( parent, dockid, wxDefaultPosition, parent->GetSize() )
378 {
379  SetLabel( _( "ToolDock" ) );
380  SetName( _( "ToolDock" ) );
381 
382  // Init
383  mManager = manager;
384  memset(mBars, 0, sizeof(mBars)); // otherwise uninitialized
385  SetBackgroundColour(theTheme.Colour( clrMedium ));
386  // Use for testing gaps
387  // SetOwnBackgroundColour( wxColour( 255, 0, 0 ) );
388 }
389 
390 //
391 // Destructer
392 //
394 {
395 }
396 
397 //
398 // Remove the toolbar from our control
399 //
401 {
402  if( mConfiguration.Contains( bar ) )
403  {
404  mConfiguration.Remove( bar );
405  }
406  mBars[ bar->GetId() ] = nullptr;
407 }
408 
409 //
410 // Handle ToolDock events
411 //
412 void ToolDock::Dock( ToolBar *bar, bool deflate, ToolBarConfiguration::Position position )
413 {
414 #ifndef __WXMAC__
415  // Apply the deflate fix only on Mac, else you introduce the opposite bug on others
416  deflate = false;
417 #endif
418 
419  // Adopt the toolbar into our family
420  bar->Reparent( this );
421  mBars[ bar->GetId() ] = bar;
422 
423  // Reset size
424  bar->SetSize(
425  // Undo the expansion that was applied when un-docking
426  bar->GetSize().x - (deflate ? 2 * ToolBarFloatMargin : 0),
427  // Don't need to adjust y the same way.
428  bar->GetDockedSize().y
429  );
430 
431  // Park the NEW bar in the correct berth
432  if (!mConfiguration.Contains(bar) && bar->IsVisible())
433  mConfiguration.Insert( bar, position );
434 
435  // Inform toolbar of change
436  bar->SetDocked( this, false );
437 
438  // Rearrange our world
439  if (bar->IsVisible())
440  LayoutToolBars();
441  Updated();
442 }
443 
444 // Initial docking of bars
446 {
447  // Add all ordered toolbars
448  for(const auto &place : GetConfiguration()) {
449  auto bar = place.pTree->pBar;
450  this->Dock(bar, false);
451  // Show it -- hidden bars are not (yet) ever saved as part of a
452  // configuration
453  Expose( bar->GetId(), true );
454  }
455 }
456 
457 // A policy object for the skeleton routine below
459 {
460 public:
461  virtual void ModifySize
463  const wxRect &,
466  wxSize &)
467  {
468  }
469 
470  virtual void Visit
471  (ToolBar *ct, wxPoint point) = 0;
472 
473  virtual bool ShouldVisitSpaces() = 0;
474 
475  virtual void FinalRect
477  {
478  }
479 };
480 
481 // Skeleton routine common to insertion of a toolbar, and figuring out
482 // width-constrained layout of toolbars
484  ToolBarConfiguration *pWrappedConfiguration)
485 {
486  if (pWrappedConfiguration)
487  pWrappedConfiguration->Clear();
488 
489  // Get size of our parent since we haven't been sized yet
490  int width, height;
491  GetParent()->GetClientSize( &width, &height );
492  width -= toolbarGap;
493  height -= toolbarGap;
494 
495  // Rectangle of space to allocate
496  wxRect main{ toolbarGap, toolbarGap,
497  // Allow limited width, but arbitrary height, for the root rectangle
498  width, std::numeric_limits<int>::max() };
499 
500  // For recording the nested subdivisions of the rectangle
501  struct Item {
502  int myBarID { NoBarID };
503  int parentBarID { NoBarID };
504  ToolBar *lastSib {};
505  ToolBar *lastWrappedChild {};
506  wxRect rect;
507  } layout[ ToolBarCount ];
508 
509  ToolBar *lastRoot {};
510  ToolBar *lastWrappedRoot {};
511 
512  // Process all docked and visible toolbars
513  for ( const auto &place : this->GetConfiguration() )
514  {
515  // Cache toolbar pointer
516  const auto ct = place.pTree->pBar;
517 
518  // set up the chain of ancestors.
519  const auto parent = place.position.rightOf;
520  const auto type = ct->GetType();
521  auto &newItem = layout[ type ];
522  newItem.parentBarID = parent ? parent->GetType() : NoBarID;
523  // Mark the slots that really were visited, for final pass through
524  // the spaces.
525  newItem.myBarID = type;
526 
527  const auto parentItem = parent ? &layout[ parent->GetType() ] : nullptr;
528  ToolBar *prevSib;
529  if (!parent) {
530  prevSib = lastRoot;
531  lastRoot = ct;
532  }
533  else {
534  auto &sib = parentItem->lastSib;
535  prevSib = sib;
536  sib = ct;
537  }
538  auto prevPosition = ToolBarConfiguration::Position{ parent, prevSib };
539 
540  // Determine the size of the toolbar to fit, with advice from
541  // the visitor object
542  wxSize sz = ct->GetSize();
543  {
544  wxRect temp;
545  temp.SetPosition(ct->GetParent()->ClientToScreen(ct->GetPosition()));
546  temp.SetSize(sz);
547  visitor.ModifySize(ct, temp, prevPosition, place.position, sz);
548  }
549 
550  // Inflate the size to leave margins
551  int tw = sz.GetWidth() + toolbarGap;
552  int th = sz.GetHeight() + toolbarGap;
553 
554  // Choose the rectangle to subdivide
555  // Find a box that we fit in by going up the tree as needed --
556  // thus when parent space is exhausted, fall back on ancestors --
557  // so if the tree has too much depth for the width of the
558  // window, the toolbars may "wrap."
559  // Can always fall back to the main rectangle even if the bar is too
560  // wide.
561  auto pItem = parentItem;
562  auto pRect = pItem ? &pItem->rect : &main;
563  while (pRect != &main)
564  {
565  // Get out if it will fit
566  bool bTooWide = tw > pRect->GetWidth();
567  // We'd like to be able to add a tall toolbar in at the start of a row,
568  // even if there isn't enough height for it.
569  // If so, we'd have to at least change how we calculate 'bTooHigh'.
570  bool bTooHigh = th > pRect->GetHeight();
571  //bTooHigh &= stack[stkcnt].GetWidth() < (width - toolbarGap);
572  //bTooHigh = false;
573 
574  if (!bTooWide && !bTooHigh)
575  break;
576 
577  if (pItem->parentBarID == NoBarID) {
578  pItem = nullptr;
579  pRect = &main;
580  }
581  else {
582  pItem = &layout[ pItem->parentBarID ];
583  pRect = &pItem->rect;
584  }
585  }
586 
587  // Record where the toolbar wrapped
588  ToolBar *& sib = pItem ? pItem->lastWrappedChild : lastWrappedRoot;
589  ToolBarConfiguration::Position newPosition {
590  pItem ? this->mBars[ pItem->myBarID ] : nullptr,
591  sib
592  };
593  sib = ct;
594  if (pWrappedConfiguration)
595  pWrappedConfiguration->Insert(ct, newPosition);
596 
597  // Place the toolbar at the upper left part of the rectangle.
598  const auto cpos = pRect->GetPosition();
599  visitor.Visit(ct, cpos);
600 
601  // Allocate an upper portion of the rectangle to this bar.
602  pRect->y += th;
603  pRect->height -= th;
604 
605  // A right portion of that upper portion remains available for
606  // descendant bars and is remembered in the layout array.
607  int x = cpos.x + tw;
608  newItem.rect = wxRect{ x, cpos.y, width - x, th };
609  }
610 
611  if (visitor.ShouldVisitSpaces()) {
612  // Visit the fringe where NEW leaves of the tree could go
613 
614  // Find the items with leftover spaces
615  const auto end = std::remove_if(layout, layout + ToolBarCount,
616  [](const Item &item){
617  return item.myBarID == NoBarID || item.rect.IsEmpty();
618  }
619  );
620  // Sort top to bottom for definiteness, though perhaps not really needed
621  std::sort(layout, end,
622  [](const Item &lhs, const Item &rhs){
623  return lhs.rect.y < rhs.rect.y;
624  }
625  );
626  for (auto iter = layout; iter != end; ++iter) {
627  const auto &item = *iter;
628  const auto &rect = item.rect;
629 
630  auto globalRect = rect;
631  globalRect.SetPosition( this->ClientToScreen(rect.GetPosition()) );
632 
633  // Let the visitor determine size
634  wxSize sz {};
636  position { this->mBars[ item.myBarID ], item.lastWrappedChild },
637  prevPosition {};
638  visitor.ModifySize(nullptr, globalRect, prevPosition, position, sz);
639  int tw = sz.GetWidth() + toolbarGap;
640  int th = sz.GetHeight() + toolbarGap;
641 
642  // Test fit
643  bool bTooWide = tw > rect.GetWidth();
644  bool bTooHigh = th > rect.GetHeight();
645  if (!bTooWide && !bTooHigh) {
646  // Call visitor again to confirm the placement
647  const auto cpos = rect.GetPosition();
648  visitor.Visit(nullptr, cpos);
649  }
650  }
651  }
652 
653  // Report the final bounding box of all the bars, and a position where
654  // you can insert a NEW bar at bottom left.
655  ToolBarConfiguration::Position finalPosition { nullptr, lastRoot };
656  visitor.FinalRect(
657  wxRect { toolbarGap, toolbarGap, main.width, main.y }, finalPosition
658  );
659 }
660 
661 //
662 // Layout the toolbars
663 //
665 {
666  struct SizeSetter final : public LayoutVisitor
667  {
668  SizeSetter (ToolDock *d) : dock{ d } {}
669 
670  void Visit
671  (ToolBar *bar, wxPoint point)
672  override
673  {
674  // Place the toolbar
675  if(bar)
676  bar->SetPosition( point );
677  }
678 
679  bool ShouldVisitSpaces() override
680  {
681  return false;
682  }
683 
684  virtual void FinalRect
685  (const wxRect &rect, ToolBarConfiguration::Position)
686  override
687  {
688  // Set the final size of the dock window
689  dock->SetMinSize( rect.GetSize() );
690  }
691 
692  ToolDock *dock;
693  } sizeSetter {
694  this
695  };
696  VisitLayout(sizeSetter, &mWrappedConfiguration);
697 
698  // Set tab order
699  {
700  ToolBar *lt{};
701  for ( const auto &place : GetConfiguration() ) {
702  auto ct = place.pTree->pBar;
703  if( lt )
704  ct->MoveAfterInTabOrder( lt );
705  lt = ct;
706  }
707  }
708 
709  // Clean things up
710  Refresh( false );
711 }
712 
713 // Determine the position where a NEW bar would be placed
714 //
715 // 'rect' will be the rectangle for the dock marker (black triangle)
717  ToolDock::PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect )
718 {
719  // Set width and size, but we must still find x and y.
720  rect = t->GetRect();
721 
722  using Position = ToolBarConfiguration::Position;
723  Position result { ToolBarConfiguration::UnspecifiedPosition };
724  struct Inserter : public LayoutVisitor
725  {
726  struct Stop {};
727 
728  Inserter(Position &p, wxRect &r, const wxPoint &pt, ToolBar *t)
729  : result(p), rect(r), point(pt), tb(t)
730  {}
731 
732  void ModifySize
733  (ToolBar *ct,
734  const wxRect &rect,
735  ToolBarConfiguration::Position prevPosition,
737  wxSize &sz)
738  override
739  {
740  // Maybe insert the NEW bar if it hasn't already been done
741  // and is in the right place.
742 
743  // Does the location fall within this bar?
744  if (rect.Contains(point))
745  {
746  sz = tb->GetDockedSize();
747  // Choose a position always, if there is a bar to displace.
748  // Else, only if the fit is possible.
749  if (ct || (sz.x <= rect.width && sz.y <= rect.height)) {
750  // May choose current or previous.
751  if (ct &&
752  (sz.y < rect.height ||
753  point.y < (rect.GetTop() + rect.GetBottom()) / 2))
754  // "Wedge" the bar into a crack alone, not adopting others,
755  // if either a short bar displaces a tall one, or else
756  // the displacing bar is at least at tall, but the pointer is
757  // in the upper half of the box.
758  usedPrev = true, result = prevPosition, result.adopt = false;
759  else
760  result = position;
761  }
762  // Now wait until the other callback below to discover x and y
763  }
764  }
765 
766  void Visit
767  (ToolBar *, wxPoint point)
768  override
769  {
771  // If we've placed it, we're done.
772  rect.x = point.x;
773  rect.y = point.y;
774  if (usedPrev)
775  rect.y -= tb->GetDockedSize().GetHeight() / 2;
776 
777  throw Stop {};
778  }
779  }
780 
781  bool ShouldVisitSpaces() override
782  {
783  return true;
784  }
785 
786  void FinalRect
787  (const wxRect &finalRect, ToolBarConfiguration::Position finalPosition)
788  override
789  {
791  // Default of all other placements.
792  result = finalPosition;
793  wxPoint point { finalRect.GetLeft(), finalRect.GetBottom() };
794  rect.SetPosition(point);
795  }
796  }
797 
798 
799  Position &result;
800  wxRect &rect;
801  const wxPoint point;
802  ToolBar *const tb;
803  bool usedPrev { false };
804  } inserter {
805  result, rect, pos, t
806  };
807 
808  try { this->VisitLayout(inserter); } catch (const Inserter::Stop&) {}
809 
810  // rect is decided
811  return result;
812 }
813 
815 {
816  backup.Clear();
817  backup.Swap(mConfiguration);
819 }
820 
822 {
825  mConfiguration.Swap(backup);
826 }
827 
828 //
829 // Set the visible/hidden state of a toolbar
830 //
831 void ToolDock::Expose( int type, bool show )
832 {
833  ToolBar *t = mBars[ type ];
834 
835  // Maintain the docked array
836  const auto shown = mConfiguration.Shows( t );
837  if( show && !shown )
838  mConfiguration.Show( t );
839  else if( !show && shown )
840  mConfiguration.Hide( t );
841 
842  // Make it (dis)appear
843  t->Expose( show );
844 
845  // Update the layout
846  LayoutToolBars();
847  Updated();
848 }
849 
850 //
851 // Queues an EVT_TOOLBAR_UPDATED command event to notify any
852 // interested parties of an updated toolbar or dock layout
853 //
855 {
856  // Queue an update event
857  wxCommandEvent e( EVT_TOOLBAR_UPDATED, GetId() );
858  GetParent()->GetEventHandler()->AddPendingEvent( e );
859 }
860 
861 //
862 // Handle grabber clicking
863 //
865 {
866  // auto pos = event.GetPosition();
867  if (!event.IsEscaping()) {
868  // Pass it on to the manager since it isn't in the handling hierarchy
869  mManager->ProcessEvent( event );
870  }
871 }
872 
873 //
874 // Handle sizing
875 //
876 void ToolDock::OnSize( wxSizeEvent & WXUNUSED(event) )
877 {
878 // event.Skip();
879 }
880 
881 //
882 // Prevent flicker
883 //
884 void ToolDock::OnErase( wxEraseEvent & WXUNUSED(event) )
885 {
886  // Ignore it to prevent flashing
887 }
888 
889 //
890 // Repaint toolbar gap lines
891 //
892 void ToolDock::OnPaint( wxPaintEvent & WXUNUSED(event) )
893 {
894  // Don't use a wxBufferedPaintDC() here. It produces a bogus
895  // background on Windows and GTK.
896  wxPaintDC dc( this );
897 
898  // Start with a clean background
899  //
900  // Under GTK, we don't set the toolbar background to the background
901  // colour in the system theme. Instead we use our own colour.
902 
903  dc.SetBackground( wxBrush( theTheme.Colour( clrMedium )));
904  dc.Clear();
905 
906  // Set the gap color
907  AColor::Dark( &dc, false );
908 
909  // Draw the initial horizontal and vertical gaps
910  wxSize sz = GetClientSize();
911 
912  AColor::Line(dc, 0, 0, sz.GetWidth(), 0 );
913  AColor::Line(dc, 0, 0, 0, sz.GetHeight() );
914 
915  // Draw the gap between each bar
916  for (const auto &place : GetConfiguration())
917  {
918  auto toolbar = place.pTree->pBar;
919  if (!toolbar)
920  continue;
921 
922  wxRect r = toolbar->GetRect();
923 
924  // Draw a horizontal line under the bar extending to the right edge of
925  // the dock
926  AColor::Line( dc,
927  r.GetLeft(),
928  r.GetBottom() + 1,
929  sz.GetWidth(),
930  r.GetBottom() + 1 );
931 
932  // For all bars but the last...
933  // ...and for bars that aren't the last in a row, draw a
934  // vertical gap line
935  if (!mConfiguration.IsRightmost(toolbar)) {
936  AColor::Line(dc,
937  r.GetRight() + 1,
938  r.GetTop(),
939  r.GetRight() + 1,
940  r.GetBottom() + 1 );
941  }
942  }
943 }
944 
945 void ToolDock::OnMouseEvents(wxMouseEvent &event)
946 {
947  // Do this hack so scrubber can detect mouse drags anywhere
948  event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
949  event.Skip();
950 }
Grabber Class.
Definition: Grabber.h:42
virtual bool ShouldVisitSpaces()=0
Position Find(const ToolBar *bar) const
Definition: ToolDock.cpp:92
bool IsRightmost(const ToolBar *bar) const
Definition: ToolDock.cpp:235
void WrapConfiguration(ToolBarConfiguration &backup)
Definition: ToolDock.cpp:814
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
bool Contains(const ToolBar *bar) const
Definition: ToolDock.h:234
void LoadConfig()
Definition: ToolDock.cpp:445
A dynamic panel where a ToolBar can be docked.
Definition: ToolDock.h:290
static bool Read(ToolBarConfiguration *pConfiguration, Legacy *pLegacy, ToolBar *bar, bool &visible, bool defaultVisible)
Definition: ToolDock.cpp:253
bool IsEscaping() const
Definition: Grabber.h:69
void InsertAtPath(ToolBar *bar, const std::vector< int > &path)
Definition: ToolDock.cpp:175
IMPLEMENT_CLASS(ToolDock, wxPanelWrapper)
ToolBarConfiguration::Position PositionBar(ToolBar *t, const wxPoint &pos, wxRect &rect)
Definition: ToolDock.cpp:717
#define toolbarGap
Definition: ToolBar.h:59
void PostRead(Legacy &legacy)
Definition: ToolDock.cpp:308
void RemoveNulls(Forest &forest)
Definition: ToolDock.cpp:296
virtual void FinalRect(const wxRect &, ToolBarConfiguration::Position)
Definition: ToolDock.cpp:476
std::pair< Forest *, Forest::iterator > FindPeers(const ToolBar *bar)
Definition: ToolDock.cpp:67
virtual bool Expose(bool show=true)
Definition: ToolBar.cpp:416
std::vector< ToolBar * > bars
Definition: ToolDock.h:255
void Dock(ToolBar *bar, bool deflate, ToolBarConfiguration::Position ndx=ToolBarConfiguration::UnspecifiedPosition)
Definition: ToolDock.cpp:412
static void Dark(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:338
void Hide(ToolBar *bar)
Definition: ToolDock.cpp:229
ToolManager * mManager
Definition: ToolDock.h:336
Iterator FindPlace(const ToolBar *bar) const
Definition: ToolDock.cpp:57
wxFileConfig * gPrefs
Definition: Prefs.cpp:72
#define EVT_GRABBER(id, fn)
Definition: Grabber.h:88
void Swap(ToolBarConfiguration &that)
Definition: ToolDock.h:57
void Remove(const ToolBar *bar)
Definition: ToolDock.cpp:210
bool IsVisible() const
Definition: ToolBar.cpp:403
ToolBarConfiguration mWrappedConfiguration
Definition: ToolDock.h:342
void Show(ToolBar *bar)
Definition: ToolDock.cpp:222
void OnGrabber(GrabberEvent &event)
Definition: ToolDock.cpp:864
ToolBarConfiguration mConfiguration
Definition: ToolDock.h:339
void swap(Tree &that)
Definition: ToolDock.h:277
virtual void Visit(ToolBar *ct, wxPoint point)=0
void Expose(int type, bool show)
Definition: ToolDock.cpp:831
static const Position UnspecifiedPosition
Definition: ToolDock.h:106
Iterator begin()
Definition: ToolDock.h:229
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
void OnMouseEvents(wxMouseEvent &event)
Definition: ToolDock.cpp:945
void OnSize(wxSizeEvent &event)
Definition: ToolDock.cpp:876
void VisitLayout(LayoutVisitor &visitor, ToolBarConfiguration *pWrappedConfiguration=nullptr)
Definition: ToolDock.cpp:483
void RestoreConfiguration(ToolBarConfiguration &backup)
Definition: ToolDock.cpp:821
ToolBar * mBars[ToolBarCount]
Definition: ToolDock.h:344
void Insert(ToolBar *bar, Position position=UnspecifiedPosition)
Definition: ToolDock.cpp:101
static void Write(const ToolBarConfiguration *pConfiguration, const ToolBar *bar)
Definition: ToolDock.cpp:329
void Undock(ToolBar *bar)
Definition: ToolDock.cpp:400
int GetType()
Definition: ToolBar.cpp:371
std::vector< Tree > Forest
Definition: ToolDock.h:53
void Updated()
Definition: ToolDock.cpp:854
Iterator end() const
Definition: ToolDock.h:230
void OnPaint(wxPaintEvent &event)
Definition: ToolDock.cpp:892
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1208
END_EVENT_TABLE()
bool Shows(const ToolBar *bar) const
Definition: ToolDock.h:247
class ToolManager
Definition: ToolManager.h:45
virtual wxSize GetDockedSize()
Definition: ToolBar.h:131
void SetDocked(ToolDock *dock, bool pushed)
Definition: ToolBar.cpp:573
Works with ToolManager and ToolDock to provide a dockable window in which buttons can be placed...
Definition: ToolBar.h:87
ToolBarConfiguration & GetConfiguration()
Definition: ToolDock.h:310
virtual void ModifySize(ToolBar *, const wxRect &, ToolBarConfiguration::Position, ToolBarConfiguration::Position, wxSize &)
Definition: ToolDock.cpp:462
void LayoutToolBars()
Definition: ToolDock.cpp:664
void OnErase(wxEraseEvent &event)
Definition: ToolDock.cpp:884