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