reapack

Package manager for REAPER
Log | Files | Refs | Submodules | README | LICENSE

dialog.hpp (4924B)


      1 /* ReaPack: Package manager for REAPER
      2  * Copyright (C) 2015-2025  Christian Fillion
      3  *
      4  * This program is free software: you can redistribute it and/or modify
      5  * it under the terms of the GNU Lesser General Public License as published by
      6  * the Free Software Foundation, either version 3 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12  * GNU Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser General Public License
     15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     16  */
     17 
     18 #ifndef REAPACK_DIALOG_HPP
     19 #define REAPACK_DIALOG_HPP
     20 
     21 #include "serializer.hpp"
     22 
     23 #include <functional>
     24 #include <map>
     25 #include <memory>
     26 #include <set>
     27 #include <vector>
     28 
     29 #include <reaper_plugin.h>
     30 #include <WDL/wdltypes.h>
     31 #include <WDL/wingui/wndsize.h>
     32 
     33 class Control;
     34 
     35 class Dialog {
     36 public:
     37   typedef std::function<void (INT_PTR)> CloseHandler;
     38 
     39   enum Modality {
     40     Modeless,
     41     Modal,
     42   };
     43 
     44   enum AnchorFlags {
     45     AnchorLeft   = 1<<0,
     46     AnchorRight  = 1<<1,
     47     AnchorTop    = 1<<2,
     48     AnchorBottom = 1<<3,
     49 
     50     AnchorLeftRight = AnchorLeft | AnchorRight,
     51     AnchorTopBottom = AnchorTop | AnchorBottom,
     52     AnchorAll = AnchorLeftRight | AnchorTopBottom,
     53   };
     54 
     55   template<class T, class... Args>
     56   static std::unique_ptr<T> Create(REAPER_PLUGIN_HINSTANCE instance,
     57     HWND parent, const CloseHandler &closeHandler, Args&&... args)
     58   {
     59     auto dlg = std::make_unique<T>(args...);
     60     dlg->m_closeHandler = closeHandler;
     61     dlg->init(instance, parent, Dialog::Modeless);
     62 
     63     return dlg;
     64   }
     65 
     66   template<class T, class... Args>
     67   static INT_PTR Show(REAPER_PLUGIN_HINSTANCE instance, HWND parent, Args&&... args)
     68   {
     69     return std::make_unique<T>(args...)->init(instance, parent, Dialog::Modal);
     70   }
     71 
     72   INT_PTR init(REAPER_PLUGIN_HINSTANCE, HWND, const Modality);
     73 
     74   REAPER_PLUGIN_HINSTANCE instance() const { return m_instance; }
     75   HWND parent() const { return m_parent; }
     76   HWND handle() const { return m_handle; }
     77 
     78   void enable() { enable(m_handle); }
     79   void enable(HWND handle) { setEnabled(true, handle); }
     80   void disable() { disable(m_handle); }
     81   void disable(HWND handle) { setEnabled(false, handle); }
     82   void setEnabled(bool enable) { setEnabled(enable, m_handle); }
     83   void setEnabled(bool, HWND);
     84   bool isChecked(HWND) const;
     85   void setChecked(bool, HWND);
     86 
     87   bool isVisible() const;
     88   void show(HWND handle = nullptr) { setVisible(true, handle); }
     89   void hide(HWND handle = nullptr) { setVisible(false, handle); }
     90   void setVisible(bool, HWND = nullptr);
     91 
     92   void close(INT_PTR = 0);
     93   void center();
     94   void boundedMove(int x, int y);
     95   bool hasFocus() const;
     96   void setFocus();
     97   int startTimer(int elapse, int id = 0, bool replace = true);
     98   void stopTimer(int id);
     99   void setClipboard(const std::string &);
    100   void setClipboard(const std::vector<std::string> &);
    101   HWND getControl(int idc);
    102   void setAnchor(HWND, int flags);
    103   void setAnchorPos(HWND, const LONG *left = nullptr, const LONG *top = nullptr,
    104     const LONG *right = nullptr, const LONG *bottom = nullptr);
    105   const POINT &minimumSize() const { return m_minimumSize; }
    106   void setMinimumSize(const POINT &p) { m_minimumSize = p; }
    107 
    108   void restoreState(Serializer::Data &);
    109   void saveState(Serializer::Data &) const;
    110 
    111 protected:
    112   enum Modifiers {
    113     AltModifier   = 1<<0,
    114     CtrlModifier  = 1<<1,
    115     ShiftModifier = 1<<2,
    116   };
    117 
    118   Dialog(int templateId);
    119   virtual ~Dialog();
    120 
    121   template<class T, class... Args>
    122   T *createControl(int id, Args&&... args)
    123   {
    124     if(m_controls.count(id))
    125       return nullptr;
    126 
    127     T *ctrl = new T(getControl(id), args...);
    128     m_controls.emplace(id, ctrl);
    129 
    130     return ctrl;
    131   }
    132 
    133   virtual void onInit();
    134   virtual void onClose();
    135   virtual void onTimer(int id);
    136   virtual void onCommand(int id, int event);
    137   virtual void onNotify(LPNMHDR, LPARAM);
    138   virtual void onContextMenu(HWND, int x, int y);
    139   virtual bool onKeyDown(int key, int mods);
    140   virtual void onResize();
    141 
    142 private:
    143   static WDL_DLGRET Proc(HWND, UINT, WPARAM, LPARAM);
    144   static int HandleKey(MSG *, accelerator_register_t *);
    145 
    146 #ifdef __APPLE__
    147   bool isTextEditUnderMouse() const;
    148 #endif
    149 
    150   const int m_template;
    151   POINT m_minimumSize;
    152   WDL_WndSizer m_resizer;
    153   Modality m_mode;
    154 
    155   REAPER_PLUGIN_HINSTANCE m_instance;
    156   HWND m_parent;
    157   HWND m_handle;
    158 
    159   using ControlPtr = std::unique_ptr<Control>;
    160   std::map<int, ControlPtr> m_controls;
    161   std::set<int> m_timers;
    162 
    163   CloseHandler m_closeHandler;
    164   accelerator_register_t m_accel;
    165 };
    166 
    167 class LockDialog {
    168 public:
    169   LockDialog(Dialog *dlg) : m_dialog(dlg)
    170   {
    171     if(m_dialog)
    172       m_dialog->disable();
    173   }
    174 
    175   ~LockDialog()
    176   {
    177     if(m_dialog)
    178       m_dialog->enable();
    179   }
    180 
    181 private:
    182   Dialog *m_dialog;
    183 };
    184 
    185 #endif