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