Audacity 3.2.0
ExpandingToolBar.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 ExpandingToolBar.cpp
6
7 Dominic Mazzoni
8
9*******************************************************************//****************************************************************//****************************************************************//****************************************************************//****************************************************************//****************************************************************//****************************************************************//*******************************************************************/
65
66#include "ExpandingToolBar.h"
67
68// For compilers that support precompilation, includes "wx/wx.h".
69#include <wx/wxprec.h>
70
71#ifndef WX_PRECOMP
72#include <wx/window.h>
73#endif
74
75#include <wx/wx.h>
76#include <wx/dcmemory.h>
77#include <wx/log.h>
78
79#include "AButton.h"
80#include "AllThemeResources.h"
81
82const int kToggleButtonHeight = 8;
83const int kMyTimerInterval = 50; // every 50 ms -> ~20 updates per second
84const wxRect kDummyRect = wxRect(-9999, -9999, 0, 0);
85
86enum {
89};
90
92{
93public:
94 std::vector<ExpandingToolBar*> childArray;
95 std::vector<wxRect> rectArray;
96 std::vector<int> rowArray;
97};
98
99//
100// ExpandingToolBar
101//
102
103BEGIN_EVENT_TABLE(ExpandingToolBar, wxPanelWrapper)
108
110
111//static
112int ExpandingToolBar::msNoAutoExpandStack = 0;
113
115 wxWindowID id,
116 const wxPoint& pos,
117 const wxSize& size):
118 wxPanelWrapper(parent, id, pos, size),
119 mIsAutoExpanded(false),
120 mIsManualExpanded(false),
121 mIsExpanded(false),
122 mAutoExpand(true),
123 mFirstTime(true),
124 mFrameParent(NULL),
125 mDialogParent(NULL),
126 mAreaParent(NULL),
127 mSavedArrangement{},
128 mTopLevelParent(NULL)
129{
130 mMainPanel = safenew wxPanelWrapper(this, -1,
131 wxDefaultPosition, wxSize(1, 1));
132 mExtraPanel = safenew wxPanelWrapper(this, -1,
133 wxDefaultPosition, wxSize(1, 1));
134
135 mGrabber = NULL;
136
137 ToolBarArea *toolBarParent =
138 dynamic_cast<ToolBarArea *>(GetParent());
139 if (toolBarParent)
140 mGrabber = safenew ToolBarGrabber(this, -1, this);
141
143 //wxImage hbar = theTheme.Image(bmpToolBarToggle);
144 //wxColour magicColor = wxColour(0, 255, 255);
145 //ImageArray fourStates = ImageRoll::SplitV(hbar, magicColor);
146/*
147 mToggleButton = safenew AButton(this, kToggleButtonID,
148 wxDefaultPosition, wxDefaultSize,
149 ImageRoll(ImageRoll::HorizontalRoll,
150 fourStates[0], magicColor),
151 ImageRoll(ImageRoll::HorizontalRoll,
152 fourStates[1], magicColor),
153 ImageRoll(ImageRoll::HorizontalRoll,
154 fourStates[2], magicColor),
155 ImageRoll(ImageRoll::HorizontalRoll,
156 fourStates[3], magicColor),
157 true);
158 mToggleButton->UseDisabledAsDownHiliteImage(true);
159*/
160 SetAutoLayout(true);
161 mTimer.SetOwner(this, kTimerID);
162}
163
165{
166}
167
168void ExpandingToolBar::OnSize(wxSizeEvent & WXUNUSED(event))
169{
171 return;
172
173 // At the time of construction, it wasn't "safe" to tell
174 // our parent that we've just joined the window, so we check
175 // for it during our first OnSize event.
176
177 if (!mFrameParent) {
178 ToolBarFrame *toolBarParent =
179 dynamic_cast<ToolBarFrame *>(GetParent());
180 if (toolBarParent) {
181 // We were placed into a floating window
182 mFrameParent = toolBarParent;
183 toolBarParent->SetChild(this);
184 }
185 }
186
187 if (!mDialogParent) {
188 ToolBarDialog *toolBarParent =
189 dynamic_cast<ToolBarDialog *>(GetParent());
190 if (toolBarParent) {
191 // We were placed into a dialog
192 mDialogParent = toolBarParent;
193 toolBarParent->SetChild(this);
194 }
195 }
196
197 if (!mAreaParent) {
198 ToolBarArea *toolBarParent =
199 dynamic_cast<ToolBarArea *>(GetParent());
200 if (toolBarParent) {
201 // We were placed into an area full of other toolbars
202 mAreaParent = toolBarParent;
203 toolBarParent->AddChild(this);
204 }
205 }
206}
207
208void ExpandingToolBar::OnToggle(wxCommandEvent & WXUNUSED(event))
209{
210 if (mIsExpanded)
211 Collapse();
212 else
213 Expand();
214}
215
217{
218 // We set both mIsManualExpanded and mIsAutoExpanded to true;
219 // that way if the user manually collapses the toolbar we set
220 // mIsManualExpanded to false but keep mIsAutoExpanded to true
221 // to prevent it from being auto-expanded again until the user
222 // actually moves the mouse completely away and back again later.
223
225 mIsManualExpanded = true;
226 mIsAutoExpanded = true;
227 Fit();
228}
229
230void ExpandingToolBar::Collapse(bool now /* = false */)
231{
232 // After being manually collapsed, we set mIsAutoExpanded back to
233 // true, which prevents it from being immediately auto-expanded
234 // again until after the mouse actually moves away and then
235 // back again later.
236
238 mIsManualExpanded = false;
239 mIsAutoExpanded = false;
240 Fit();
241 mIsAutoExpanded = true;
242
243 if (now) {
245
246 MoveDrawer(wxSize(0, 0));
247 }
248}
249
251{
253 mIsManualExpanded == false && mIsAutoExpanded == false) {
255 mIsAutoExpanded = true;
256 Fit();
257 }
258}
259
261{
262#ifdef EXPERIMENTAL_ROLL_UP_DIALOG
263 if (mIsAutoExpanded == true && mIsManualExpanded == false) {
265 mIsAutoExpanded = false;
266 Fit();
267 }
268#endif
269}
270
271class ExpandingToolBarEvtHandler final : public wxEvtHandler
272{
273 public:
275 wxWindow *window,
276 wxEvtHandler *inheritedEvtHandler)
277 {
278 mToolBar = toolbar;
279 mWindow = window;
280 mInheritedEvtHandler = inheritedEvtHandler;
281
282 window->PushEventHandler(this);
283}
284
285 bool ProcessEvent(wxEvent& evt) override
286 {
287// if (mToolBar->IsCursorInWindow())
289// else
290// mToolBar->TryAutoExpand();
291
292 return mInheritedEvtHandler->ProcessEvent(evt);
293 }
294
296 {
297 mWindow->RemoveEventHandler(this);
298 }
299
300protected:
302 wxWindow *mWindow;
303 wxEvtHandler *mInheritedEvtHandler;
304
305 DECLARE_NO_COPY_CLASS(ExpandingToolBarEvtHandler)
306};
307
309{
310 if (!mWindowHash[win]) {
311 mHandlers.push_back(std::make_unique<ExpandingToolBarEvtHandler>
312 (this, win, win->GetEventHandler()));
313 mWindowHash[win] = 1;
314 }
315
316 wxWindowList children = win->GetChildren();
317 for(auto child : children)
319}
320
322{
323 mMainSize = mMainPanel->GetBestSize();
324 mExtraSize = mExtraPanel->GetBestSize();
325 mButtonSize = wxSize(wxMax(mMainSize.x, mExtraSize.x),
327
328 int left = 0;
329
330 if (mGrabber) {
331 mGrabberSize = mGrabber->GetMinSize();
332 left += mGrabberSize.x;
333 }
334 else
335 mGrabberSize = wxSize(0, 0);
336
337 mMainPanel->SetSize(left, 0, mMainSize.x, mMainSize.y);
338 mToggleButton->SetSize(left, mMainSize.y, mButtonSize.x, mButtonSize.y);
339 mExtraPanel->SetSize(left, mMainSize.y + mButtonSize.y,
341
342 if (mGrabber)
343 mGrabber->SetSize(0, 0, left, mMainSize.y + mButtonSize.y);
344
345 // Add event handlers to all children
346 //RecursivelyPushEventHandlers(this);
347
348 return true;
349}
350
352{
353#ifdef EXPERIMENTAL_ROLL_UP_DIALOG
355#else
356 mIsExpanded = true;// JKC - Wedge it open at all times.
357#endif
358
359 int width = mButtonSize.x + mGrabberSize.x;
360
361 wxSize baseWindowSize = wxSize(width,
362 mMainSize.y + mButtonSize.y);
363
364 mTargetDrawerSize = wxSize(mButtonSize.x, 0);
365
366 if (mIsExpanded)
368
370
371 // The first time, we always update the size. Otherwise, we set
372 // a target size, and the actual size changes during a timer
373 // event.
374
375 if (mFirstTime) {
376 mFirstTime = false;
377 mCurrentDrawerSize = wxSize(mExtraSize.x, 0);
378 mCurrentTotalSize = baseWindowSize;
379
380 SetMinSize(mCurrentTotalSize);
381 SetMaxSize(mCurrentTotalSize);
382 SetSize(mCurrentTotalSize);
383 }
384
385 // wxTimers seem to be a little unreliable - sometimes they stop for
386 // no good reason, so this "primes" it every now and then...
387 mTimer.Stop();
389}
390
392{
393 wxPoint globalMouse = ::wxGetMousePosition();
394 wxPoint localMouse = ScreenToClient(globalMouse);
395
396 bool result = (localMouse.x >= 0 && localMouse.y >= 0 &&
397 localMouse.x < mCurrentTotalSize.x &&
398 localMouse.y < mCurrentTotalSize.y);
399
400 // The grabber doesn't count!
401 if (mGrabber && mGrabber->GetRect().Contains(localMouse))
402 result = false;
403
404 return result;
405}
406
408{
409 // This is how we make sure the extra panel, which slides out
410 // like a drawer, appears on top of everything else in the window...
411
412 wxPoint pos;
413 pos.x = mGrabberSize.x;
414 pos.y = mMainSize.y + mButtonSize.y;
415 wxWindow *frame = this;
416 while(!frame->IsTopLevel()) {
417 pos += frame->GetPosition();
418 frame = frame->GetParent();
419 }
420
421 mExtraPanel->Reparent(frame);
422 mExtraPanel->SetPosition(pos);
423}
424
425void ExpandingToolBar::MoveDrawer(wxSize prevSize)
426{
428 mMainSize.y +
429 mButtonSize.y +
431
432 if (mFrameParent) {
433 // If we're in a tool window
434
435 SetMinSize(mCurrentTotalSize);
436 SetMaxSize(mCurrentTotalSize);
437 SetSize(mCurrentTotalSize);
438
439 GetParent()->Fit();
440 }
441
442 if (mDialogParent) {
443 // If we're in a dialog
444
445 SetMinSize(mCurrentTotalSize);
446 SetMaxSize(mCurrentTotalSize);
447 SetSize(mCurrentTotalSize);
448
449 GetParent()->Fit();
450 }
451
452 if (mAreaParent) {
453 // If we're in a tool area
454
455 if (mCurrentDrawerSize.y > 0 && prevSize.y == 0) {
457 mExtraPanel->Show();
458 }
459
460 mExtraPanel->SetMinSize(mCurrentDrawerSize);
461 mExtraPanel->SetMaxSize(mCurrentDrawerSize);
463
464 if (mCurrentDrawerSize.y == 0)
465 mExtraPanel->Hide();
466 }
467}
468
469void ExpandingToolBar::OnTimer(wxTimerEvent & WXUNUSED(event))
470{
474 else if (!IsCursorInWindow())
476
478 return;
479
480 // This accelerates the current size towards the target size;
481 // it's a neat way for the window to roll open, but in such a
482 // way that it
483
484 wxSize prevSize = mCurrentDrawerSize;
486 if (abs((mCurrentDrawerSize-mTargetDrawerSize).x)<2 &&
489
490 MoveDrawer(prevSize);
491}
492
494{
495 wxSize size = GetClientSize();
496 wxBitmap bitmap(size.x, size.y);
497 wxClientDC winDC(this);
498 wxMemoryDC memDC;
499 memDC.SelectObject(bitmap);
500 memDC.Blit(0, 0, size.x, size.y,
501 &winDC, 0, 0);
502 return bitmap;
503}
504
506{
507 if (!mAreaParent)
508 return;
509
510 int j;
511
513
514 mTimer.Stop();
515
516 // This gives time for wx to finish redrawing the window that way.
517 // HACK: why do we need to do it so many times???
518 for(j=0; j<500; j++)
519 ::wxSafeYield();
520
521 wxBitmap toolbarBitmap = GetToolbarBitmap();
522
526
527 mAreaParent->Refresh(true);
528
529 mTopLevelParent = this;
530 while(!mTopLevelParent->IsTopLevel())
531 mTopLevelParent = mTopLevelParent->GetParent();
532
533 wxPoint hotSpot = ScreenToClient(wxGetMousePosition());
534
535 hotSpot -= (ClientToScreen(wxPoint(0, 0)) -
536 mAreaParent->ClientToScreen(wxPoint(0, 0)));
537
540
541 wxColour magicColor = wxColour(0, 255, 255);
542// wxImage tgtImage = theTheme.Image(bmpToolBarTarget);
543// ImageRoll tgtImageRoll = ImageRoll(ImageRoll::VerticalRoll,
544// tgtImage,
545// magicColor);
546 mTargetPanel = safenew wxPanelWrapper(mAreaParent, -1, //tgtImageRoll,
547 wxDefaultPosition,
548 wxDefaultSize,
549 wxTRANSPARENT_WINDOW);
550 mTargetPanel->SetSize(mDropTarget);
551
552 // This gives time for wx to finish redrawing the window that way.
553 // HACK: why do we need to do it several times???
554 for(j=0; j<500; j++)
555 ::wxSafeYield();
556
558
559 mDragImage = std::make_unique<wxDragImage>(toolbarBitmap);
560 mDragImage->BeginDrag(hotSpot, mAreaParent, mTopLevelParent);
561 mDragImage->Show();
562 mDragImage->Move(ScreenToClient(wxGetMousePosition()));
563}
564
566{
568 return;
569
570 wxPoint cursorPos = mAreaParent->ScreenToClient(wxGetMousePosition());
571 wxRect prevTarget = mDropTarget;
572 int best_dist_sq = 99999;
573 int i;
574
575 for(i = 0; i < (int)mDropTargets.size(); i++) {
576 int x = (mDropTargets[i].x + (mDropTargets[i].width/2))-cursorPos.x;
577 int y = (mDropTargets[i].y + (mDropTargets[i].height/2))-cursorPos.y;
578 int dist_sq = (x*x) + (y*y);
579
580 if (dist_sq < best_dist_sq) {
581 best_dist_sq = dist_sq;
583 }
584 }
585
586 if (!mAreaParent->GetRect().Contains(cursorPos))
588
589 if (mDropTarget != prevTarget) {
590 mDragImage->Hide();
591
592 wxRect r = mDropTarget;
593 r.Inflate(4, 4);
594 mTargetPanel->SetSize(r);
595
596 #if 0
597 wxClientDC dc(mAreaParent);
598 dc.DestroyClippingRegion();
599 dc.SetLogicalFunction(wxINVERT);
600 wxRect r = prevTarget;
601 r.Inflate(4, 4);
602 dc.DrawRectangle(r);
603 r = mDropTarget;
604 r.Inflate(4, 4);
605 dc.DrawRectangle(r);
606 #endif
607
608 // This gives time for wx to finish redrawing the window that way.
609 // HACK: why do we need to do it so many times???
610 for(i=0; i<500; i++)
611 ::wxSafeYield();
612
613 mDragImage->Show();
614 mDragImage->Move(ScreenToClient(wxGetMousePosition()));
615 }
616 else
617 mDragImage->Move(ScreenToClient(wxGetMousePosition()));
618}
619
621{
623 return;
624
625 // DELETE mTargetPanel; // I think this is not needed, but unreachable anyway -- PRL
626
628
629 mDragImage->Hide();
630 mDragImage->EndDrag();
631
633
634 if (mDropTarget == kDummyRect) {
636 }
637 else {
638 mSavedArrangement.reset();
640 }
641
642 // Keep all drawers closed until the user moves specifically to a
643 // different window
645
646 mTopLevelParent->Refresh(true);
647
649}
650
651//
652// ToolBarGrabber
653//
654
655BEGIN_EVENT_TABLE(ToolBarGrabber, wxPanelWrapper)
656 EVT_PAINT(ToolBarGrabber::OnPaint)
657 EVT_SIZE(ToolBarGrabber::OnSize)
658 EVT_MOUSE_EVENTS(ToolBarGrabber::OnMouse)
660
662
664 wxWindowID id,
665 ExpandingToolBar *ownerToolbar,
666 const wxPoint& pos,
667 const wxSize& size):
668 wxPanelWrapper(parent, id, pos, size),
669 mOwnerToolBar(ownerToolbar)
670{
671#if 0
672 wxImage grabberImages = theTheme.Image(bmpToolBarGrabber);
673 wxColour magicColor = wxColour(0, 255, 255);
674 ImageArray images = ImageRoll::SplitH(grabberImages, magicColor);
675
676 mImageRoll[0] = ImageRoll(ImageRoll::VerticalRoll,
677 images[0],
678 magicColor);
679 mImageRoll[1] = ImageRoll(ImageRoll::VerticalRoll,
680 images[1],
681 magicColor);
682
683 SetMinSize(mImageRoll[0].GetMinSize());
684 SetMaxSize(mImageRoll[1].GetMaxSize());
685#endif
686 mState = 0;
687}
688
689void ToolBarGrabber::OnMouse(wxMouseEvent &event)
690{
691 int prevState = mState;
692
693 // Handle highlighting the image if the mouse is over it
694
695 if (event.Entering())
696 mState = 1;
697 else if (event.Leaving())
698 mState = 0;
699 else {
700 wxSize clientSize = GetClientSize();
701
702 if (event.m_x >= 0 && event.m_y >= 0 &&
703 event.m_x < clientSize.x && event.m_y < clientSize.y)
704 mState = 1;
705 else
706 mState = 0;
707 }
708
709 if (event.ButtonDown())
711
712 if (mState != prevState)
713 Refresh(false);
714}
715
716void ToolBarGrabber::OnPaint(wxPaintEvent & WXUNUSED(event))
717{
718 wxPaintDC dc(this);
719
720 // mImageRoll[mState].Draw(dc, GetClientRect());
721}
722
723void ToolBarGrabber::OnSize(wxSizeEvent & WXUNUSED(event))
724{
725 Refresh(false);
726}
727
728//
729// ToolBarDialog
730//
731
732BEGIN_EVENT_TABLE(ToolBarDialog, wxDialogWrapper)
734
736
737ToolBarDialog::ToolBarDialog(wxWindow* parent,
738 wxWindowID id,
740 const wxPoint& pos):
741 wxDialogWrapper(parent, id, name, pos, wxSize(1, 1),
742// Workaround for bug in __WXMSW__. No close box on a wxDialog unless wxSYSTEM_MENU is used.
743#ifdef __WXMSW__
744 wxSYSTEM_MENU |
745#endif
746 wxCAPTION|wxCLOSE_BOX),
747 mChild(NULL)
748{
749}
750
752{
753}
754
756{
757 mChild = child;
758 if (mChild && mChild->GetParent() != this)
759 mChild->Reparent(this);
760
761 Fit();
762}
763
765{
766 if (mChild) {
767 wxSize childSize = mChild->GetBestSize();
768
769 // Take into account the difference between the content
770 // size and the frame size
771 wxSize curContentSize = GetClientSize();
772 wxSize curFrameSize = GetSize();
773 wxSize newFrameSize = childSize + (curFrameSize - curContentSize);
774
775 SetSizeHints(newFrameSize, newFrameSize);
776 SetSize(newFrameSize);
777 }
778}
779
780//
781// ToolBarFrame
782//
783
784BEGIN_EVENT_TABLE(ToolBarFrame, wxMiniFrame)
786
787IMPLEMENT_CLASS(ToolBarFrame, wxMiniFrame)
788
789ToolBarFrame::ToolBarFrame(wxWindow* parent,
790 wxWindowID id,
791 const wxString& name,
792 const wxPoint& pos):
793 wxMiniFrame(parent, id, name, pos, wxSize(1, 1),
794// Workaround for bug in __WXMSW__. No close box on a miniframe unless wxSYSTEM_MENU is used.
795#ifdef __WXMSW__
796 wxSYSTEM_MENU |
797#endif
798 wxCAPTION|wxCLOSE_BOX),
799 mChild(NULL)
800{
801}
802
804{
805}
806
808{
809 mChild = child;
810 if (mChild && mChild->GetParent() != this)
811 mChild->Reparent(this);
812
813 Fit();
814}
815
817{
818 if (mChild) {
819 wxSize childSize = mChild->GetBestSize();
820
821 // Take into account the difference between the content
822 // size and the frame size
823 wxSize curContentSize = GetClientSize();
824 wxSize curFrameSize = GetSize();
825 wxSize newFrameSize = childSize + (curFrameSize - curContentSize);
826
827 SetSizeHints(newFrameSize, newFrameSize);
828 SetSize(newFrameSize);
829 }
830}
831
832//
833// ToolBarArea
834//
835
836BEGIN_EVENT_TABLE(ToolBarArea, wxPanelWrapper)
837 EVT_SIZE(ToolBarArea::OnSize)
838 EVT_MOUSE_EVENTS(ToolBarArea::OnMouse)
840
842
843ToolBarArea::ToolBarArea(wxWindow* parent,
844 wxWindowID id,
845 const wxPoint& pos,
846 const wxSize& size):
847 wxPanelWrapper(parent, id, pos, size),
848 mInOnSize(false),
849 mCapturedChild(NULL)
850{
851
852}
853
855{
856}
857
858void ToolBarArea::ContractRow(int rowIndex)
859{
860 // Contract all of the toolbars in a given row to their
861 // minimum size. This is an intermediate step in layout.
862
863 int i;
864 int x = 0;
865
866 for(i = 0; i < (int)mChildArray.size(); i++)
867 if (mRowArray[i] == rowIndex) {
868 wxPoint childPos = mChildArray[i]->GetPosition();
869 wxSize childMin = mChildArray[i]->GetMinSize();
870
871 mChildArray[i]->SetSize(x, childPos.y,
872 childMin.x, childMin.y);
873 x += childMin.x;
874 }
875}
876
877bool ToolBarArea::ExpandRow(int rowIndex)
878{
879 // Expand all of the toolbars in a given row so that the
880 // whole width is filled, if possible. This is the last
881 // step after laying out as many toolbars as possible in
882 // that row. Returns false if it's not possible to fit
883 // all of these toolbars in one row anymore.
884
885 wxSize area = GetClientSize();
886 int i, j, x;
887 int minWidth = 0;
888 int leftoverSpace = 0;
889 int expandableCount = 0;
890 int toolbarCount = 0;
891
892 for(i = 0; i < (int)mChildArray.size(); i++)
893 if (mRowArray[i] == rowIndex) {
894 ExpandingToolBar *child = mChildArray[i];
895 wxSize childMin = child->GetMinSize();
896 wxSize childMax = child->GetMaxSize();
897
898 minWidth += childMin.x;
899
900 toolbarCount++;
901 if (childMax.x > childMin.x)
902 expandableCount++;
903 }
904
905 leftoverSpace = area.x - minWidth;
906
907 if (leftoverSpace <= 0) {
908 if (toolbarCount > 1)
909 return false; // not possible to fit all in one row
910 else
911 return true; // there's only one, so it doesn't matter
912 }
913
914 j = 0;
915 x = 0;
916 for(i = 0; i < (int)mChildArray.size(); i++)
917 if (mRowArray[i] == rowIndex) {
918 ExpandingToolBar *child = mChildArray[i];
919 wxPoint childPos = child->GetPosition();
920 wxSize childMin = child->GetMinSize();
921 wxSize childMax = child->GetMaxSize();
922
923 int width = childMin.x;
924
925 if (childMax.x > childMin.x)
926 width +=
927 (leftoverSpace * (j+1) / expandableCount) -
928 (leftoverSpace * (j) / expandableCount);
929
930 mChildArray[i]->SetSize(x, childPos.y,
931 width, childMin.y);
932 x += width;
933 j++;
934 }
935
936 return true; // success
937}
938
939void ToolBarArea::LayoutOne(int childIndex)
940{
941 wxSize area = GetClientSize();
942 ExpandingToolBar *child = mChildArray[childIndex];
943 wxSize childMin = child->GetMinSize();
944
945 if (childIndex == 0) {
946 mRowArray[childIndex] = 0;
947 mChildArray[childIndex]->SetSize(0, 0, childMin.x, childMin.y);
948 ExpandRow(0);
949
950 #if 0
951 wxPoint p = mChildArray[childIndex]->GetPosition();
952 wxSize s = mChildArray[childIndex]->GetSize();
953
954 wxPrintf("ToolBar %d moved to row %d at (%d, %d), size (%d x %d)\n",
955 childIndex, mRowArray[childIndex],
956 p.x, p.y, s.x, s.y);
957 #endif
958
959 mLastLayoutSize = area;
960
961 return;
962 }
963
964 int prevRow = mRowArray[childIndex-1];
965 ContractRow(prevRow);
966 wxPoint prevPos = mChildArray[childIndex-1]->GetPosition();
967 wxSize prevSize = mChildArray[childIndex-1]->GetSize();
968
969 int prevX = prevPos.x + prevSize.x;
970 int availableWidth = area.x - prevX;
971
972 if (childMin.x <= availableWidth) {
973 // It fits into the same row
974 mRowArray[childIndex] = prevRow;
975 mChildArray[childIndex]->SetSize(prevX, prevPos.y,
976 childMin.x, childMin.y);
977 ExpandRow(prevRow);
978 }
979 else {
980 // Go to the next row
981 ExpandRow(prevRow);
982 mRowArray[childIndex] = prevRow + 1;
983
984 int i;
985 int maxRowHeight = 0;
986 for(i=0; i<childIndex; i++)
987 if (mRowArray[i] == prevRow &&
988 mChildArray[i]->GetSize().y > maxRowHeight)
989 maxRowHeight = mChildArray[i]->GetSize().y;
990
991 mChildArray[childIndex]->SetSize(0, prevPos.y + maxRowHeight,
992 childMin.x, childMin.y);
993 ExpandRow(prevRow+1);
994 }
995
996 // Save the size of the window the last time we moved one of the
997 // toolbars around. If the user does a minor resize, we try to
998 // preserve the layout. If the user does a major resize, we're
999 // allowed to redo the layout.
1000 mLastLayoutSize = area;
1001
1002 #if 0
1003 wxPoint p = mChildArray[childIndex]->GetPosition();
1004 wxSize s = mChildArray[childIndex]->GetSize();
1005
1006 wxPrintf("ToolBar %d moved to row %d at (%d, %d), size (%d x %d)\n",
1007 childIndex, mRowArray[childIndex],
1008 p.x, p.y, s.x, s.y);
1009 #endif
1010}
1011
1013{
1014 // Redo the layout from scratch, preserving only the order of
1015 // the children
1016
1017 int i;
1018
1019 for(i = 0; i < (int)mChildArray.size(); i++)
1020 mRowArray[i] = -1;
1021
1022 for(i = 0; i < (int)mChildArray.size(); i++)
1023 LayoutOne(i);
1024
1025 Refresh(true);
1026
1027 return true;
1028}
1029
1031{
1032 // Try to modify the layout as little as possible - but if that's
1033 // impossible, redo the layout as necessary.
1034
1035 int row = -1;
1036 int i, j;
1037
1038 for(i = 0; i < (int)mChildArray.size(); i++) {
1039 if (mRowArray[i] > row) {
1040 row = mRowArray[i];
1041 bool success = ExpandRow(row);
1042 if (!success) {
1043 // Re-layout all toolbars from this row on
1044 for(j = i; j < (int)mChildArray.size(); j++)
1045 LayoutOne(j);
1046 return;
1047 }
1048 }
1049 }
1050}
1051
1053{
1054 Fit(true, true);
1055}
1056
1057void ToolBarArea::Fit(bool horizontal, bool vertical)
1058{
1059 wxSize clientSize = GetClientSize();
1060 wxSize minSize;
1061 wxSize maxSize;
1062 wxSize actualSize;
1063 int i;
1064
1065 minSize.x = 0;
1066 minSize.y = 0;
1067 maxSize.x = 9999;
1068 maxSize.y = 0;
1069 for(i = 0; i < (int)mChildArray.size(); i++) {
1070 wxPoint childPos = mChildArray[i]->GetPosition();
1071 wxSize childSize = mChildArray[i]->GetSize();
1072
1073 if (childPos.x + childSize.x > actualSize.x) {
1074 actualSize.x = childPos.x + childSize.x;
1075 }
1076
1077 if (childSize.x > minSize.x) {
1078 minSize.x = childSize.x;
1079 }
1080
1081 if (childPos.y + childSize.y > maxSize.y) {
1082 maxSize.y = childPos.y + childSize.y;
1083 minSize.y = maxSize.y;
1084 actualSize.y = maxSize.y;
1085 }
1086 }
1087
1088 if (!horizontal && actualSize.x < clientSize.x)
1089 actualSize.x = clientSize.x;
1090 if (!vertical && actualSize.y < clientSize.y)
1091 actualSize.y = clientSize.y;
1092
1093 if (minSize != mMinSize ||
1094 maxSize != mMaxSize) {
1095 mMinSize = minSize;
1096 mMaxSize = maxSize;
1097 SetMinSize(mMinSize);
1098 SetMaxSize(mMaxSize);
1099 }
1100 if (actualSize != mActualSize) {
1101 mActualSize = actualSize;
1102 SetSize(mActualSize);
1103 }
1104}
1105
1106void ToolBarArea::OnSize(wxSizeEvent & WXUNUSED(event))
1107{
1108 if (mInOnSize)
1109 return;
1110
1111 mInOnSize = true;
1112
1113 wxSize currentSize = GetClientSize();
1114
1115 if (abs(currentSize.x - mLastLayoutSize.x) >= 100) {
1116 // If they resize by more than 100 pixels (horizontally),
1117 // we totally redo the layout, preserving the order of the
1118 // toolbars but not the exact position.
1119 Layout();
1120 }
1121 else {
1122 // If it was a minor resize, we try to preserve the positions of
1123 // the toolbars. If this is impossible, we still redo the layout,
1124 // of course.
1125 AdjustLayout();
1126 }
1127
1128 Fit(false, true);
1129
1130 mInOnSize = false;
1131}
1132
1133void ToolBarArea::OnMouse(wxMouseEvent &evt)
1134{
1135 if (mCapturedChild) {
1136 if (evt.ButtonUp())
1138 else if (evt.Moving() || evt.Dragging())
1140 }
1141 else {
1142 evt.Skip();
1143 }
1144}
1145
1147{
1148 int i;
1149
1150 for(i = 0; i < (int)mChildArray.size(); i++)
1151 mChildArray[i]->Collapse(now);
1152}
1153
1155{
1156 mChildArray.push_back(child);
1157 mRowArray.push_back(-1); // unknown row
1158 LayoutOne(mChildArray.size() - 1);
1159 Fit(false, true);
1160}
1161
1163{
1164 int i, j;
1165
1166 for(i = 0; i < (int)mChildArray.size(); i++) {
1167 if (mChildArray[i] == child) {
1168 child->Hide();
1169
1170 mChildArray.erase(mChildArray.begin() + i);
1171 mRowArray.erase(mRowArray.begin() + i);
1172
1173 for(j = i; j < (int)mChildArray.size(); j++)
1174 mRowArray[j] = -1;
1175
1176 for(j = i; j < (int)mChildArray.size(); j++)
1177 LayoutOne(j);
1178
1179 Fit(false, true);
1180 }
1181 }
1182}
1183
1184std::unique_ptr<ToolBarArrangement> ToolBarArea::SaveArrangement()
1185{
1186 auto arrangement = std::make_unique<ToolBarArrangement>();
1187 int i;
1188
1189 arrangement->childArray = mChildArray;
1190 arrangement->rowArray = mRowArray;
1191
1192 for(i = 0; i < (int)mChildArray.size(); i++)
1193 arrangement->rectArray.push_back(mChildArray[i]->GetRect());
1194
1195 return arrangement;
1196}
1197
1198void ToolBarArea::RestoreArrangement(std::unique_ptr<ToolBarArrangement>&& arrangement)
1199{
1200 int i;
1201
1202 mChildArray = arrangement->childArray;
1203 mRowArray = arrangement->rowArray;
1204
1205 for(i = 0; i < (int)mChildArray.size(); i++) {
1206 mChildArray[i]->SetSize(arrangement->rectArray[i]);
1207 mChildArray[i]->Show();
1208 }
1209
1210 Fit(false, true);
1211
1212 arrangement.reset();
1213}
1214
1215std::vector<wxRect> ToolBarArea::GetDropTargets()
1216{
1217 mDropTargets.clear();
1218 mDropTargetIndices.clear();
1219 mDropTargetRows.clear();
1220
1221 int numChildren = (int)mChildArray.size();
1222 int i;
1223 int row = -1;
1224
1225 if (numChildren == 0)
1226 return mDropTargets;
1227
1228 for(i=0; i<numChildren; i++) {
1229 int childRow = mRowArray[i];
1230 wxRect childRect = mChildArray[i]->GetRect();
1231
1232 if (childRow != row) {
1233 // Add a target before this child (at beginning of row only)
1234 row = childRow;
1235 mDropTargetIndices.push_back(i);
1236 mDropTargetRows.push_back(row);
1237 mDropTargets.push_back(wxRect(childRect.x, childRect.y,
1238 0, childRect.height));
1239 }
1240
1241 // Add a target after this child (always)
1242 mDropTargetIndices.push_back(i+1);
1243 mDropTargetRows.push_back(row);
1244 mDropTargets.push_back(wxRect(childRect.x+childRect.width, childRect.y,
1245 0, childRect.height));
1246 }
1247
1248 return mDropTargets;
1249}
1250
1251void ToolBarArea::MoveChild(ExpandingToolBar *toolBar, wxRect dropTarget)
1252{
1253 int i, j;
1254
1255 for(i = 0; i < (int)mDropTargets.size(); i++) {
1256 if (dropTarget == mDropTargets[i]) {
1257 int newIndex = mDropTargetIndices[i];
1258 int newRow = mDropTargetRows[i];
1259
1260 mChildArray.insert(mChildArray.begin() + newIndex, toolBar);
1261 mRowArray.insert(mRowArray.begin() + newIndex, newRow);
1262
1263 for(j = newIndex+1; j < (int)mChildArray.size(); j++)
1264 mRowArray[j] = -1;
1265
1266 ContractRow(newRow);
1267
1268 mChildArray[newIndex]->Show();
1269
1270 for(j = newIndex; j < (int)mChildArray.size(); j++)
1271 LayoutOne(j);
1272
1273 Fit(false, true);
1274
1275 return;
1276 }
1277 }
1278}
1279
1281{
1282 mCapturedChild = child;
1283}
wxImage(22, 22)
IMPLEMENT_CLASS(AudioSetupToolBar, ToolBar)
END_EVENT_TABLE()
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
Definition: Distortion.cpp:76
struct State mState
@ kTimerID
@ kToggleButtonID
const int kToggleButtonHeight
const int kMyTimerInterval
const wxRect kDummyRect
std::vector< wxImage > ImageArray
Definition: ImageRoll.h:25
#define safenew
Definition: MemoryX.h:9
THEME_API Theme theTheme
Definition: Theme.cpp:82
void PushDown()
Definition: AButton.cpp:577
void PopUp()
Definition: AButton.cpp:585
A custom event handler for ExpandingToolBar.
ExpandingToolBarEvtHandler(ExpandingToolBar *toolbar, wxWindow *window, wxEvtHandler *inheritedEvtHandler)
bool ProcessEvent(wxEvent &evt) override
A smart ToolBar class that has a "MainPanel" which is always displayed, and an "ExtraPanel" that can ...
wxWindow * mTopLevelParent
std::unique_ptr< wxDragImage > mDragImage
void OnTimer(wxTimerEvent &evt)
void OnSize(wxSizeEvent &evt)
void RecursivelyPushEventHandlers(wxWindow *win)
void MoveDrawer(wxSize prevSize)
ToolBarArea * mAreaParent
WindowHash mWindowHash
static int msNoAutoExpandStack
std::vector< wxRect > mDropTargets
std::vector< std::unique_ptr< ExpandingToolBarEvtHandler > > mHandlers
void OnToggle(wxCommandEvent &evt)
std::unique_ptr< ToolBarArrangement > mSavedArrangement
bool Layout() override
ToolBarGrabber * mGrabber
ToolBarFrame * mFrameParent
AButton * mToggleButton
ToolBarDialog * mDialogParent
void Fit() override
wxBitmap GetToolbarBitmap()
void Collapse(bool now=false)
An ImageRoll is an image that can be expanded to an arbitrary size; it is made up of both fixed piece...
Definition: ImageRoll.h:28
@ VerticalRoll
Definition: ImageRoll.h:34
static ImageArray SplitH(const wxImage &src, wxColour magicColor)
Definition: ImageRoll.cpp:109
wxImage & Image(int iIndex)
An alternative to ToolBarFrame which can contain an ExpandingToolBar. ToolBarArea is used for a 'dock...
wxSize mLastLayoutSize
ExpandingToolBar * mCapturedChild
bool ExpandRow(int rowIndex)
void SetCapturedChild(ExpandingToolBar *child)
void ContractRow(int rowIndex)
std::vector< int > mDropTargetIndices
std::unique_ptr< ToolBarArrangement > SaveArrangement()
std::vector< int > mRowArray
std::vector< ExpandingToolBar * > mChildArray
std::vector< wxRect > mDropTargets
void CollapseAll(bool now=false)
std::vector< wxRect > GetDropTargets()
void OnMouse(wxMouseEvent &evt)
void AddChild(ExpandingToolBar *child)
void Fit() override
void OnSize(wxSizeEvent &evt)
std::vector< int > mDropTargetRows
void LayoutOne(int childIndex)
void MoveChild(ExpandingToolBar *child, wxRect dropTarget)
void RestoreArrangement(std::unique_ptr< ToolBarArrangement > &&arrangement)
void RemoveChild(ExpandingToolBar *child)
bool Layout() override
Small class that holds some layout information for an ExpandingToolBar.
std::vector< ExpandingToolBar * > childArray
std::vector< int > rowArray
std::vector< wxRect > rectArray
A dialog based container for ExpandingToolBars providing modal based operations.
void Fit() override
ExpandingToolBar * mChild
void SetChild(ExpandingToolBar *child)
A miniframe based container for ExpandingToolBars providing modeless presentation.
ExpandingToolBar * mChild
void SetChild(ExpandingToolBar *child)
void Fit() override
Draws the grabber for an ExpandingToolBar.
void OnPaint(wxPaintEvent &evt)
void OnSize(wxSizeEvent &evt)
void OnMouse(wxMouseEvent &evt)
ExpandingToolBar * mOwnerToolBar
Holds a msgid for the translation catalog; may also bind format arguments.