/**********************************************************************

  Audacity: A Digital Audio Editor

  ToolBar.h

  Dominic Mazzoni
  Shane T. Mueller
  Leland Lucius

**********************************************************************/

#ifndef __AUDACITY_TOOLBAR__
#define __AUDACITY_TOOLBAR__

#include <functional>
#include <vector>
#include <wx/defs.h>

#include "Prefs.h"
#include "Theme.h"
#include "wxPanelWrapper.h" // to inherit
#include <wx/windowptr.h>

class wxBoxSizer;
class wxDC;
class wxEraseEvent;
class wxMouseEvent;
class wxObject;
class wxPaintEvent;
class wxPoint;
class wxSize;
class wxSizeEvent;
class wxString;
class wxWindow;

class AButton;
class Grabber;
class ToolDock;

class ToolBarResizer;

////////////////////////////////////////////////////////////
/// class ToolBar
////////////////////////////////////////////////////////////

//
// Custom event
//
DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_TOOLBAR_UPDATED, -1);

/// Height of a single line toolbar
constexpr static auto toolbarSingle { 31 };
/// Preferred inner toolbar margin 
constexpr static auto toolbarMargin { 5 };
/// Preferred spacing between inner toolbar elements
constexpr static auto toolbarSpacing { 2 };
//constexpr static auto toolbarGap {  }

//
// Size of border around toolbars
//
#define toolbarGap 1

// How may pixels padding each side of a floating toolbar
enum { ToolBarFloatMargin = 1 };

class AudacityProject;

class AUDACITY_DLL_API ToolBar /* not final */
: public wxPanelWrapper
, protected PrefsListener
{

 public:

   using Holder = wxWindowPtr<ToolBar>;

   ToolBar( AudacityProject &project,
      const TranslatableString & label, const Identifier &section,
      bool resizable = false);
   virtual ~ToolBar();

   //! Whether the toolbar should be shown by default.  Default implementation returns true
   virtual bool ShownByDefault() const;

   //! Default implementation returns false
   virtual bool HideAfterReset() const;

   //! Identifies one of the docking areas for toolbars
   enum DockID {
      TopDockID = 1,
      BotDockID = 2
   };

   //! Which dock the toolbar defaults into.  Default implementation chooses the top dock
   virtual DockID DefaultDockID() const;

   bool AcceptsFocus() const override { return false; };
   bool AcceptsFocusFromKeyboard() const override;

   virtual void SetToDefaultSize();
   //NEW virtuals:
   virtual void Create(wxWindow *parent);
   virtual void EnableDisableButtons() = 0;
   virtual void ReCreateButtons();
   void UpdatePrefs() override;
   virtual void RegenerateTooltips() = 0;

   //! Get a value used for computing cascading positions of undocked bars
   int GetIndex() const { return mIndex; }
   //! Set a value used for computing cascading positions of undocked bars
   void SetIndex(int index) { mIndex = index; }

   TranslatableString GetTitle();
   TranslatableString GetLabel();
   Identifier GetSection();
   ToolDock *GetDock();

   void SetPreferredNeighbors(Identifier left, Identifier top = {});

private:
   void SetLabel(const wxString & label) override;
public:
   void SetLabel(const TranslatableString & label);
   virtual void SetDocked(ToolDock *dock, bool pushed);

   //! Defaults to (NoBarID, NoBarId)
   std::pair<Identifier, Identifier> PreferredNeighbors() const noexcept;

   // NEW virtual:
   virtual bool Expose(bool show = true);

   bool IsResizable() const;
   bool IsVisible() const;
   bool IsDocked() const;
   bool IsPositioned(){ return mPositioned; };
   void SetVisible( bool bVisible );
   void SetPositioned(){ mPositioned = true;};

   /// Resizable toolbars should implement these.
   // NEW virtuals:
   virtual int GetInitialWidth() { return -1; }
   virtual int GetMinToolbarWidth() { return GetInitialWidth(); }
   virtual wxSize GetDockedSize() { return GetMinSize(); }
   
   // Utility function for certain resizable toolbars.
   // Allows them to dock at normal or double size.
   wxSize GetSmartDockedSize();

 public:
   static
   AButton *MakeButton(wxWindow *parent,
                       teBmps eUp,
                       teBmps eDown,
                       teBmps eHilite,
                       teBmps eDownHi,
                       teBmps eStandardUp,
                       teBmps eStandardDown,
                       teBmps eDisabled,
                       wxWindowID id,
                       wxPoint placement,
                       bool processdownevents,
                       wxSize size);


   static
   AButton *MakeButton(ToolBar *parent,
                       teBmps eEnabledUp,
                       teBmps eEnabledDown,
                       teBmps eDisabled,
                       int id,
                       bool processdownevents,
                       const TranslatableString &label);

   static
   void MakeAlternateImages(AButton &button, int idx,
                            teBmps eUp,
                            teBmps eDown,
                            teBmps eHilite,
                            teBmps eDownHi,
                            teBmps eStandardUp,
                            teBmps eStandardDown,
                            teBmps eDisabled,
                            wxSize size);

   static
   void SetButtonToolTip
      (AudacityProject &project, AButton &button,
       // If a shortcut key is defined for the command, then it is appended,
       // parenthesized, after the translated name.
       const ComponentInterfaceSymbol commands[], size_t nCommands);

   static void MakeButtonBackgroundsSmall();
   static void MakeButtonBackgroundsLarge();
   virtual void ResizingDone() {};

 protected:
   void SetButton(bool down, AButton *button);

   static void MakeMacRecoloredImage(teBmps eBmpOut, teBmps eBmpIn);
   static void MakeMacRecoloredImageSize(teBmps eBmpOut, teBmps eBmpIn, const wxSize& size);
   static void MakeRecoloredImage(teBmps eBmpOut, teBmps eBmpIn);
   static void MakeRecoloredImageSize(teBmps eBmpOut, teBmps eBmpIn, const wxSize& size);

   wxBoxSizer *GetSizer();

   void Add(wxWindow *window,
            int proportion = 0,
            int flag = wxALIGN_TOP,
            int border = 0,
            wxObject *userData = NULL);

   // Takes ownership of sizer
   void Add(wxSizer *sizer,
             int proportion = 0,
             int flag = 0,
             int border = 0,
             wxObject *userData = NULL);

   void Add(int width,
            int height,
            int proportion = 0,
            int flag = 0,
            int border = 0,
            wxObject *userData = NULL);

   void AddSpacer(int size = 14);
   void AddStretchSpacer(int prop = 1);

   void Detach(wxWindow *window);
   void Detach(wxSizer *sizer);

   void Updated();

   /// Returns the width in pixels of the resizer element
   int GetResizeGrabberWidth();

   virtual void Populate() = 0;
   virtual void Repaint(wxDC *dc) = 0;

   void OnErase(wxEraseEvent & event);
   void OnPaint(wxPaintEvent & event);
   void OnMouseEvents(wxMouseEvent &event);

 protected:
   AudacityProject &mProject;
   TranslatableString mLabel;
   Identifier mSection;
   int mIndex{0};
 private:
   void Init(wxWindow *parent, int type, const wxString & title, const wxString & label);

   wxWindow *mParent;

   Grabber *mGrabber;
   ToolBarResizer *mResizer;

   wxBoxSizer *mHSizer;

   Identifier mPreferredLeftNeighbor;
   Identifier mPreferredTopNeighbor;

   bool mVisible;
   bool mResizable;
   bool mPositioned; // true if position floating determined.

 public:

   DECLARE_CLASS(ToolBar)
   DECLARE_EVENT_TABLE()

   friend class ToolBarResizer;
};

struct AUDACITY_DLL_API RegisteredToolbarFactory {
   using Function = std::function< ToolBar::Holder( AudacityProject & ) >;
   using Functions = std::vector< Function >;

   RegisteredToolbarFactory( const Function &function );

   static const Functions &GetFactories();
};

#endif
