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