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

  Audacity: A Digital Audio Editor

  Grabber.cpp

  Leland Lucius

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

\file Grabber.cpp

  Implements Grabber

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

\class Grabber
\brief The widget to the left of a ToolBar that allows it to be dragged
around to NEW positions.

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

#ifndef __AUDACITY_WIDGETS_GRABBER__
#define __AUDACITY_WIDGETS_GRABBER__

#include "../Audacity.h"

#include "wx/defs.h"
#include "wx/dc.h"
#include "wx/event.h"
#include "wx/gdicmn.h"
#include "wx/window.h"

////////////////////////////////////////////////////////////
/// Grabber Class
////////////////////////////////////////////////////////////

// Custom events

DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_GRABBER_CLICKED, -1)

class GrabberEvent final : public wxCommandEvent
{
 public:

   GrabberEvent(wxEventType type = wxEVT_NULL,
                wxWindowID winid = 0,
                const wxPoint& pt = wxDefaultPosition,
                bool escaping = false)
   : wxCommandEvent(type, winid)
   {
      mPos = pt;
      mEscaping = escaping;
   }

   GrabberEvent(const GrabberEvent & event) = default;

   // Position of event (in screen coordinates)
   const wxPoint & GetPosition() const
   {
      return mPos;
   }

   void SetPosition(const wxPoint & pos)
   {
      mPos = pos;
   }

   bool IsEscaping() const { return mEscaping; }

   // Clone is required by wxwidgets; implemented via copy constructor
   wxEvent *Clone() const override
   {
      return safenew GrabberEvent(*this);
   }

 protected:

   wxPoint mPos;
   bool mEscaping {};
};

typedef void (wxEvtHandler::*GrabberEventFunction)(GrabberEvent &);

#define GrabberEventHandler(func) \
    (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(GrabberEventFunction, &func)

#define EVT_GRABBER(id, fn) \
    DECLARE_EVENT_TABLE_ENTRY(EVT_GRABBER_CLICKED, id, wxID_ANY, \
    (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) \
    wxStaticCastEvent(GrabberEventFunction, & fn), (wxObject *) NULL),

// Specifies how wide the grabber will be

#define grabberWidth 10

class Grabber final : public wxWindow
{

 public:

   Grabber(wxWindow *parent, wxWindowID id);
   virtual ~Grabber();

   // We don't need or want to accept focus since there's really
   // not a need to dock/float a toolbar from the keyboard.  If this
   // changes, remove this and add the necessary keyboard movement
   // handling.
   // Note that AcceptsFocusFromKeyboard() rather than AcceptsFocus()
   // is overridden so that ESC can cancel toolbar drag.
   bool AcceptsFocusFromKeyboard() const override {return false;}

   void PushButton(bool state);
   void SetAsSpacer( bool bIsSpacer );

 protected:

   void OnLeftDown(wxMouseEvent & event);
   void OnEnter(wxMouseEvent & event);
   void OnLeave(wxMouseEvent & event);
   void OnPaint(wxPaintEvent & event);
   void OnKeyDown(wxKeyEvent & event);

 private:

   void DrawGrabber(wxDC & dc);
   void SendEvent(wxEventType type, const wxPoint & pos, bool escaping);

   bool mOver;
   bool mPressed;
   bool mAsSpacer;

 public:

   DECLARE_EVENT_TABLE()
};

#endif
