1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-03 14:13:11 +02:00
audacity/src/toolbars/ToolDock.h
James Crook 7661d179ba Send size event after repopulating MeterToolbar buttons.
If we don't do this, it does not regain its former size, if it is floating.
2017-04-27 09:51:34 +01:00

349 lines
8.6 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
ToolDock.h
Dominic Mazzoni
Shane T. Mueller
Leland Lucius
**********************************************************************/
#ifndef __AUDACITY_TOOLDOCK__
#define __AUDACITY_TOOLDOCK__
#include <vector>
#include "../MemoryX.h" // for std::move
#include <wx/defs.h>
#include "ToolBar.h"
class wxCommandEvent;
class wxEraseEvent;
class wxSizeEvent;
class wxPaintEvent;
class wxPoint;
class wxRect;
class wxWindow;
class GrabberEvent;
class ToolManager;
////////////////////////////////////////////////////////////
/// class ToolDock
////////////////////////////////////////////////////////////
//
// ToolDock IDs
//
enum
{
NoDockID = 0,
TopDockID,
BotDockID,
DockCount = 2
};
class ToolBarConfiguration
{
struct Tree;
using Forest = std::vector<Tree>;
public:
void Swap(ToolBarConfiguration &that)
{
mForest.swap(that.mForest);
}
void Clear()
{
mForest.clear();
}
struct Position {
ToolBar *rightOf {};
ToolBar *below {};
bool adopt {true};
bool valid {true};
// Default constructor
Position() {}
Position(
ToolBar *r,
ToolBar *b = nullptr,
bool shouldAdopt = true
)
: rightOf{ r }, below{ b }, adopt{ shouldAdopt }
{}
// Constructor for the invalid value
explicit Position(bool /* dummy */) : valid{ false } {}
friend inline bool operator ==
(const Position &lhs, const Position &rhs)
{ return lhs.valid == rhs.valid &&
(!lhs.valid ||
(lhs.rightOf == rhs.rightOf
&& lhs.below == rhs.below
&& lhs.adopt == rhs.adopt
));
}
friend inline bool operator !=
(const Position &lhs, const Position &rhs)
{ return !(lhs == rhs); }
};
static const Position UnspecifiedPosition;
struct Place {
Tree *pTree {};
Position position;
};
// This iterator visits the nodes of the forest in pre-order, and at each
// stop, makes the parent, previous sibling, and children accessible.
class Iterator
: public std::iterator<std::forward_iterator_tag, Place>
{
public:
const Place &operator * () const { return mPlace; }
const Place *operator -> () const { return &**this; }
Iterator &operator ++ ()
{
// This is a feature: advance position even at the end
mPlace.position =
{ mPlace.pTree ? mPlace.pTree->pBar : nullptr };
if (!mIters.empty())
{
auto triple = &mIters.back();
auto &children = triple->current->children;
if (children.empty()) {
while (++triple->current == triple->end) {
mIters.pop_back();
if (mIters.empty())
break;
triple = &mIters.back();
}
}
else {
auto b = children.begin();
mIters.push_back( Triple { b, b, children.end() } );
}
}
if (mIters.empty()) {
mPlace.pTree = nullptr;
// Leave mPlace.position as above
}
else {
const auto &triple = mIters.back();
mPlace.pTree = &*triple.current;
if (mIters.size() == 1)
mPlace.position.rightOf = nullptr;
else
mPlace.position.rightOf = (mIters.rbegin() + 1)->current->pBar;
if (triple.begin == triple.current)
mPlace.position.below = nullptr;
else
mPlace.position.below = (triple.current - 1)->pBar;
}
return *this;
}
// This may be called on the end iterator, and then returns empty
std::vector<int> GetPath() const
{
std::vector<int> path;
path.reserve(mIters.size());
for (const auto &triple : mIters)
path.push_back(triple.current - triple.begin);
return path;
}
friend inline bool operator ==
(const Iterator &lhs, const Iterator &rhs)
{
const auto &li = lhs.mIters;
const auto &ri = rhs.mIters;
return li.size() == ri.size() &&
std::equal(li.begin(), li.end(), ri.begin());
}
friend inline bool operator !=
(const Iterator &lhs, const Iterator &rhs)
{
return !(lhs == rhs);
}
private:
friend ToolBarConfiguration;
Iterator () {}
explicit Iterator(ToolBarConfiguration &conf)
{
auto &forest = conf.mForest;
if (!forest.empty()) {
auto b = forest.begin();
mIters.push_back( Triple { b, b, forest.end() } );
mPlace.pTree = &*b;
}
}
Place mPlace;
using FIter = Forest::iterator;
struct Triple
{
Triple (FIter b, FIter c, FIter e)
: begin{b}, current{c}, end{e} {}
FIter begin, current, end;
friend inline bool operator ==
(const Triple &lhs, const Triple &rhs)
{
// Really need only to compare current
return
// lhs.begin == rhs.begin &&
lhs.current == rhs.current
// lhs.end == rhs.end
;
}
};
std::vector<Triple> mIters;
};
Iterator begin() { return Iterator { *this }; }
Iterator end() const { return Iterator {}; }
Position Find(const ToolBar *bar) const;
bool Contains(const ToolBar *bar) const
{
return Find(bar) != UnspecifiedPosition;
}
// Default position inserts at the end
void Insert(ToolBar *bar,
Position position = UnspecifiedPosition);
void InsertAtPath(ToolBar *bar, const std::vector<int> &path);
void Remove(const ToolBar *bar);
// Future: might allow a state that the configuration remembers
// a hidden bar, but for now, it's equivalent to Contains():
bool Shows(const ToolBar *bar) const { return Contains(bar); }
void Show(ToolBar *bar);
void Hide(ToolBar *bar);
bool IsRightmost(const ToolBar *bar) const;
struct Legacy {
std::vector<ToolBar*> bars;
};
static bool Read
(ToolBarConfiguration *pConfiguration,
Legacy *pLegacy,
ToolBar *bar, bool &visible, bool defaultVisible);
void PostRead(Legacy &legacy);
static void Write
(const ToolBarConfiguration *pConfiguration, const ToolBar *bar);
private:
void Remove(Forest &forest, Forest::iterator iter);
void RemoveNulls(Forest &forest);
struct Tree
{
ToolBar *pBar {};
Forest children;
void swap(Tree &that)
{
std::swap(pBar, that.pBar);
children.swap(that.children);
}
};
Iterator FindPlace(const ToolBar *bar) const;
std::pair<Forest*, Forest::iterator> FindParent(const ToolBar *bar);
Forest mForest;
};
class ToolDock final : public wxPanelWrapper
{
public:
ToolDock( ToolManager *manager, wxWindow *parent, int dockid );
~ToolDock();
bool AcceptsFocus() const override { return false; };
void LoadConfig();
void LayoutToolBars();
void Expose( int type, bool show );
int GetOrder( ToolBar *bar );
void Dock( ToolBar *bar, bool deflate,
ToolBarConfiguration::Position ndx
= ToolBarConfiguration::UnspecifiedPosition);
void Undock( ToolBar *bar );
ToolBarConfiguration::Position
PositionBar( ToolBar *t, const wxPoint & pos, wxRect & rect );
ToolBarConfiguration &GetConfiguration()
{ return mConfiguration; }
// backup gets old contents of the configuration; the configuration is
// set to the wrapped configuration.
void WrapConfiguration(ToolBarConfiguration &backup);
// Reverse what was done by WrapConfiguration.
void RestoreConfiguration(ToolBarConfiguration &backup);
void Updated();
protected:
void OnErase( wxEraseEvent & event );
void OnSize( wxSizeEvent & event );
void OnPaint( wxPaintEvent & event );
void OnGrabber( GrabberEvent & event );
void OnMouseEvents(wxMouseEvent &event);
private:
class LayoutVisitor;
void VisitLayout(LayoutVisitor &visitor,
ToolBarConfiguration *pWrappedConfiguration = nullptr);
int mTotalToolBarHeight;
wxWindow *mParent;
ToolManager *mManager;
// Stores adjacency relations that we want to realize in the dock layout
ToolBarConfiguration mConfiguration;
// Configuration as modified by the constraint of the main window width
ToolBarConfiguration mWrappedConfiguration;
ToolBar *mBars[ ToolBarCount ];
public:
DECLARE_CLASS( ToolDock )
DECLARE_EVENT_TABLE()
};
#endif