DISTRHO Plugin Framework
DistrhoUI.hpp
1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any purpose with
6  * or without fee is hereby granted, provided that the above copyright notice and this
7  * permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10  * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #ifndef DISTRHO_UI_HPP_INCLUDED
18 #define DISTRHO_UI_HPP_INCLUDED
19 
20 #include "extra/LeakDetector.hpp"
21 #include "src/DistrhoPluginChecks.h"
22 
23 #ifdef DGL_CAIRO
24 # include "Cairo.hpp"
25 #endif
26 #ifdef DGL_OPENGL
27 # include "OpenGL.hpp"
28 #endif
29 #ifdef DGL_VULKAN
30 # include "Vulkan.hpp"
31 #endif
32 
33 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
34 # include "../dgl/Base.hpp"
35 # include "extra/ExternalWindow.hpp"
36 typedef DISTRHO_NAMESPACE::ExternalWindow UIWidget;
37 #elif DISTRHO_UI_USE_CUSTOM
38 # include DISTRHO_UI_CUSTOM_INCLUDE_PATH
39 typedef DISTRHO_UI_CUSTOM_WIDGET_TYPE UIWidget;
40 #elif DISTRHO_UI_USE_CAIRO
41 # include "../dgl/Cairo.hpp"
42 typedef DGL_NAMESPACE::CairoTopLevelWidget UIWidget;
43 #elif DISTRHO_UI_USE_NANOVG
44 # include "../dgl/NanoVG.hpp"
45 typedef DGL_NAMESPACE::NanoTopLevelWidget UIWidget;
46 #else
47 # include "../dgl/TopLevelWidget.hpp"
48 typedef DGL_NAMESPACE::TopLevelWidget UIWidget;
49 #endif
50 
51 #if DISTRHO_UI_FILE_BROWSER
52 # include "extra/FileBrowserDialog.hpp"
53 #endif
54 
56 
57 class PluginWindow;
58 
59 /* ------------------------------------------------------------------------------------------------------------
60  * DPF UI */
61 
62 /**
63  @addtogroup MainClasses
64  @{
65  */
66 
67 /**
68  DPF UI class from where UI instances are created.
69 
70  @note You must call setSize during construction,
71  @TODO Detailed information about this class.
72  */
73 class UI : public UIWidget
74 {
75 public:
76  /**
77  UI class constructor.
78  The UI should be initialized to a default state that matches the plugin side.
79 
80  When @a automaticallyScale is set to true, DPF will automatically scale up the UI
81  to fit the host/desktop scale factor.@n
82  It assumes aspect ratio is meant to be kept.
83  Manually call setGeometryConstraints instead if keeping UI aspect ratio is not required.
84  */
85  UI(uint width = 0, uint height = 0, bool automaticallyScaleAndSetAsMinimumSize = false);
86 
87  /**
88  Destructor.
89  */
90  ~UI() override;
91 
92  /* --------------------------------------------------------------------------------------------------------
93  * Host state */
94 
95  /**
96  Check if this UI window is resizable (by the user or window manager).
97  There are situations where an UI supports resizing but the plugin host does not, so this could return false.
98 
99  You might want to add a resize handle for such cases, so the user is still allowed to resize the window.
100  (programatically resizing a window is always possible, but the same is not true for the window manager)
101  */
102  bool isResizable() const noexcept;
103 
104  /**
105  Get the color used for UI background (i.e. window color) in RGBA format.
106  Returns 0 by default, in case of error or lack of host support.
107 
108  The following example code can be use to extract individual colors:
109  ```
110  const int red = (bgColor >> 24) & 0xff;
111  const int green = (bgColor >> 16) & 0xff;
112  const int blue = (bgColor >> 8) & 0xff;
113  ```
114  */
115  uint getBackgroundColor() const noexcept;
116 
117  /**
118  Get the color used for UI foreground (i.e. text color) in RGBA format.
119  Returns 0xffffffff by default, in case of error or lack of host support.
120 
121  The following example code can be use to extract individual colors:
122  ```
123  const int red = (fgColor >> 24) & 0xff;
124  const int green = (fgColor >> 16) & 0xff;
125  const int blue = (fgColor >> 8) & 0xff;
126  ```
127  */
128  uint getForegroundColor() const noexcept;
129 
130  /**
131  Get the current sample rate used in plugin processing.
132  @see sampleRateChanged(double)
133  */
134  double getSampleRate() const noexcept;
135 
136  /**
137  Get the bundle path where the UI resides.@n
138  Can return null if the UI is not available in a bundle (if it is a single binary).
139  @see getBinaryFilename
140  */
141  const char* getBundlePath() const noexcept;
142 
143  /**
144  editParameter.
145 
146  Touch/pressed-down event.
147  Lets the host know the user is tweaking a parameter.
148  Required in some hosts to record automation.
149  */
150  void editParameter(uint32_t index, bool started);
151 
152  /**
153  setParameterValue.
154 
155  Change a parameter value in the Plugin.
156  */
157  void setParameterValue(uint32_t index, float value);
158 
159 #if DISTRHO_PLUGIN_WANT_STATE
160  /**
161  setState.
162  @TODO Document this.
163  */
164  void setState(const char* key, const char* value);
165 
166  /**
167  Request a new file from the host, matching the properties of a state key.@n
168  This will use the native host file browser if available, otherwise a DPF built-in file browser is used.@n
169  Response will be sent asynchronously to stateChanged, with the matching key and the new file as the value.@n
170  It is not possible to know if the action was cancelled by the user.
171 
172  @return Success if a file-browser was opened, otherwise false.
173  @note You cannot request more than one file at a time.
174  */
175  bool requestStateFile(const char* key);
176 #endif
177 
178 #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
179  /**
180  Send a single MIDI note from the UI to the plugin DSP side.@n
181  A note with zero velocity will be sent as note-off (MIDI 0x80), otherwise note-on (MIDI 0x90).
182  */
183  void sendNote(uint8_t channel, uint8_t note, uint8_t velocity);
184 #endif
185 
186 #if DISTRHO_UI_FILE_BROWSER
187  /**
188  Open a file browser dialog with this window as transient parent.@n
189  A few options can be specified to setup the dialog.
190 
191  If a path is selected, onFileSelected() will be called with the user chosen path.
192  If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename.
193 
194  This function does not block the event loop.
195 
196  @note This is exactly the same API as provided by the Window class,
197  but redeclared here so that non-embed/DGL based UIs can still use file browser related functions.
198  */
199  bool openFileBrowser(const DISTRHO_NAMESPACE::FileBrowserOptions& options = FileBrowserOptions());
200 #endif
201 
202 #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
203  /* --------------------------------------------------------------------------------------------------------
204  * Direct DSP access - DO NOT USE THIS UNLESS STRICTLY NECESSARY!! */
205 
206  /**
207  getPluginInstancePointer.
208  @TODO Document this.
209  */
210  void* getPluginInstancePointer() const noexcept;
211 #endif
212 
213 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
214  /* --------------------------------------------------------------------------------------------------------
215  * External UI helpers */
216 
217  /**
218  Get the bundle path that will be used for the next UI.
219  @note: This function is only valid during createUI(),
220  it will return null when called from anywhere else.
221  */
222  static const char* getNextBundlePath() noexcept;
223 
224  /**
225  Get the scale factor that will be used for the next UI.
226  @note: This function is only valid during createUI(),
227  it will return 1.0 when called from anywhere else.
228  */
229  static double getNextScaleFactor() noexcept;
230 
231 # if DISTRHO_PLUGIN_HAS_EMBED_UI
232  /**
233  Get the Window Id that will be used for the next created window.
234  @note: This function is only valid during createUI(),
235  it will return 0 when called from anywhere else.
236  */
237  static uintptr_t getNextWindowId() noexcept;
238 # endif
239 #endif
240 
241 protected:
242  /* --------------------------------------------------------------------------------------------------------
243  * DSP/Plugin Callbacks */
244 
245  /**
246  A parameter has changed on the plugin side.@n
247  This is called by the host to inform the UI about parameter changes.
248  */
249  virtual void parameterChanged(uint32_t index, float value) = 0;
250 
251 #if DISTRHO_PLUGIN_WANT_PROGRAMS
252  /**
253  A program has been loaded on the plugin side.@n
254  This is called by the host to inform the UI about program changes.
255  */
256  virtual void programLoaded(uint32_t index) = 0;
257 #endif
258 
259 #if DISTRHO_PLUGIN_WANT_STATE
260  /**
261  A state has changed on the plugin side.@n
262  This is called by the host to inform the UI about state changes.
263  */
264  virtual void stateChanged(const char* key, const char* value) = 0;
265 #endif
266 
267  /* --------------------------------------------------------------------------------------------------------
268  * DSP/Plugin Callbacks (optional) */
269 
270  /**
271  Optional callback to inform the UI about a sample rate change on the plugin side.
272  @see getSampleRate()
273  */
274  virtual void sampleRateChanged(double newSampleRate);
275 
276  /* --------------------------------------------------------------------------------------------------------
277  * UI Callbacks (optional) */
278 
279  /**
280  UI idle function, called to give idle time to the plugin UI directly from the host.
281  This is called right after OS event handling and Window idle events (within the same cycle).
282  There are no guarantees in terms of timing.
283  @see addIdleCallback(IdleCallback*, uint).
284  */
285  virtual void uiIdle() {}
286 
287  /**
288  Window scale factor function, called when the scale factor changes.
289  This function is for plugin UIs to be able to override Window::onScaleFactorChanged(double).
290 
291  The default implementation does nothing.
292  WARNING function needs a proper name
293  */
294  virtual void uiScaleFactorChanged(double scaleFactor);
295 
296 #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
297  /**
298  Get the types available for the data in a clipboard.
299  Must only be called within the context of uiClipboardDataOffer.
300  */
301  std::vector<DGL_NAMESPACE::ClipboardDataOffer> getClipboardDataOfferTypes();
302 
303  /**
304  Window clipboard data offer function, called when clipboard has data present, possibly with several datatypes.
305  While handling this event, the data types can be investigated with getClipboardDataOfferTypes() to decide whether to accept the offer.
306 
307  Reimplement and return a non-zero id to accept the clipboard data offer for a particular type.
308  UIs must ignore any type they do not recognize.
309 
310  The default implementation accepts the "text/plain" mimetype.
311  */
312  virtual uint32_t uiClipboardDataOffer();
313 
314  /**
315  Windows focus function, called when the window gains or loses the keyboard focus.
316  This function is for plugin UIs to be able to override Window::onFocus(bool, CrossingMode).
317 
318  The default implementation does nothing.
319  */
320  virtual void uiFocus(bool focus, DGL_NAMESPACE::CrossingMode mode);
321 
322  /**
323  Window reshape function, called when the window is resized.
324  This function is for plugin UIs to be able to override Window::onReshape(uint, uint).
325 
326  The plugin UI size will be set right after this function.
327  The default implementation sets up the drawing context where necessary.
328 
329  You should almost never need to override this function.
330  The most common exception is custom OpenGL setup, but only really needed for custom OpenGL drawing code.
331  */
332  virtual void uiReshape(uint width, uint height);
333 #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
334 
335 #if DISTRHO_UI_FILE_BROWSER
336  /**
337  Window file selected function, called when a path is selected by the user, as triggered by openFileBrowser().
338  This function is for plugin UIs to be able to override Window::onFileSelected(const char*).
339 
340  This action happens after the user confirms the action, so the file browser dialog will be closed at this point.
341  The default implementation does nothing.
342 
343  If you need to use files as plugin state, please setup and use states with kStateIsFilenamePath instead.
344  */
345  virtual void uiFileBrowserSelected(const char* filename);
346 #endif
347 
348  /* --------------------------------------------------------------------------------------------------------
349  * UI Resize Handling, internal */
350 
351 #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
352  /**
353  External Window resize function, called when the window is resized.
354  This is overriden here so the host knows when the UI is resized by you.
355  @see ExternalWindow::sizeChanged(uint,uint)
356  */
357  void sizeChanged(uint width, uint height) override;
358 #else
359  /**
360  Widget resize function, called when the widget is resized.
361  This is overriden here so the host knows when the UI is resized by you.
362  @see Widget::onResize(const ResizeEvent&)
363  */
364  void onResize(const ResizeEvent& ev) override;
365 #endif
366 
367  // -------------------------------------------------------------------------------------------------------
368 
369 private:
370  struct PrivateData;
371  PrivateData* const uiData;
372  friend class PluginWindow;
373  friend class UIExporter;
374 #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
375  /** @internal */
376  void requestSizeChange(uint width, uint height) override;
377 #endif
378 
379  DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI)
380 };
381 
382 /** @} */
383 
384 /* ------------------------------------------------------------------------------------------------------------
385  * Create UI, entry point */
386 
387 /**
388  @addtogroup EntryPoints
389  @{
390  */
391 
392 /**
393  createUI.
394  @TODO Document this.
395  */
396 extern UI* createUI();
397 
398 /** @} */
399 
400 // -----------------------------------------------------------------------------------------------------------
401 
403 
404 #endif // DISTRHO_UI_HPP_INCLUDED
Definition: DistrhoUI.hpp:74
void * getPluginInstancePointer() const noexcept
virtual void stateChanged(const char *key, const char *value)=0
void editParameter(uint32_t index, bool started)
virtual void programLoaded(uint32_t index)=0
const char * getBundlePath() const noexcept
uint getBackgroundColor() const noexcept
void sizeChanged(uint width, uint height) override
static uintptr_t getNextWindowId() noexcept
bool requestStateFile(const char *key)
uint getForegroundColor() const noexcept
UI(uint width=0, uint height=0, bool automaticallyScaleAndSetAsMinimumSize=false)
bool isResizable() const noexcept
void setParameterValue(uint32_t index, float value)
double getSampleRate() const noexcept
~UI() override
void sendNote(uint8_t channel, uint8_t note, uint8_t velocity)
static double getNextScaleFactor() noexcept
static const char * getNextBundlePath() noexcept
virtual void parameterChanged(uint32_t index, float value)=0
void setState(const char *key, const char *value)
virtual void sampleRateChanged(double newSampleRate)
virtual void uiScaleFactorChanged(double scaleFactor)
virtual void uiIdle()
Definition: DistrhoUI.hpp:285
UI * createUI()
#define END_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:834
#define START_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:828
#define DISTRHO_UI_CUSTOM_WIDGET_TYPE
Definition: DistrhoInfo.hpp:619
Definition: FileBrowserDialogImpl.hpp:33