DISTRHO Plugin Framework
Window.hpp
1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2021 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 DGL_WINDOW_HPP_INCLUDED
18 #define DGL_WINDOW_HPP_INCLUDED
19 
20 #include "Geometry.hpp"
21 
22 START_NAMESPACE_DGL
23 
24 class Application;
25 class TopLevelWidget;
26 
27 // -----------------------------------------------------------------------
28 
29 /**
30  DGL Window class.
31 
32  This is the where all OS-related events initially happen, before being propagated to any widgets.
33 
34  A Window MUST have an Application instance tied to it.
35  It is not possible to swap Application instances from within the lifetime of a Window.
36  But it is possible to completely change the Widgets that a Window contains during its lifetime.
37 
38  Typically the event handling functions as following:
39  Application -> Window -> Top-Level-Widget -> SubWidgets
40 
41  Please note that, unlike many other graphical toolkits out there,
42  DGL makes a clear distinction between a Window and a Widget.
43  You cannot directly draw in a Window, you need to create a Widget for that.
44 
45  Also, a Window MUST have a single top-level Widget.
46  The Window will take care of global screen positioning and resizing, everything else is sent for widgets to handle.
47 
48  ...
49  */
50 class Window
51 {
52 public:
53 #ifndef DGL_FILE_BROWSER_DISABLED
54  /**
55  File browser options.
56  @see Window::openFileBrowser
57  */
59  /**
60  File browser button state.
61  This allows to customize the behaviour of the file browse dialog buttons.
62  */
63  enum ButtonState {
64  kButtonInvisible,
65  kButtonVisibleUnchecked,
66  kButtonVisibleChecked,
67  };
68 
69  /** Start directory, uses current working directory if null */
70  const char* startDir;
71  /** File browser dialog window title, uses "FileBrowser" if null */
72  const char* title;
73  /** File browser dialog window width */
74  uint width;
75  /** File browser dialog window height */
76  uint height;
77  // TODO file filter
78 
79  /**
80  File browser buttons.
81  */
82  struct Buttons {
83  /** Whether to list all files vs only those with matching file extension */
85  /** Whether to show hidden files */
87  /** Whether to show list of places (bookmarks) */
89 
90  /** Constuctor for default values */
92  : listAllFiles(kButtonVisibleChecked),
93  showHidden(kButtonVisibleUnchecked),
94  showPlaces(kButtonVisibleUnchecked) {}
95  } buttons;
96 
97  /** Constuctor for default values */
99  : startDir(nullptr),
100  title(nullptr),
101  width(0),
102  height(0),
103  buttons() {}
104  };
105 #endif // DGL_FILE_BROWSER_DISABLED
106 
107  /**
108  Constructor for a regular, standalone window.
109  */
110  explicit Window(Application& app);
111 
112  /**
113  Constructor for a modal window, by having another window as its parent.
114  The Application instance must be the same between the 2 windows.
115  */
116  explicit Window(Application& app, Window& parent);
117 
118  /**
119  Constructor for an embed Window without known size,
120  typically used in modules or plugins that run inside another host.
121  */
122  explicit Window(Application& app,
123  uintptr_t parentWindowHandle,
124  double scaleFactor,
125  bool resizable);
126 
127  /**
128  Constructor for an embed Window with known size,
129  typically used in modules or plugins that run inside another host.
130  */
131  explicit Window(Application& app,
132  uintptr_t parentWindowHandle,
133  uint width,
134  uint height,
135  double scaleFactor,
136  bool resizable);
137 
138  /**
139  Destructor.
140  */
141  virtual ~Window();
142 
143  /**
144  Whether this Window is embed into another (usually not DGL-controlled) Window.
145  */
146  bool isEmbed() const noexcept;
147 
148  /**
149  Check if this window is visible / mapped.
150  Invisible windows do not receive events except resize.
151  @see setVisible(bool)
152  */
153  bool isVisible() const noexcept;
154 
155  /**
156  Set windows visible (or not) according to @a visible.
157  Only valid for standalones, embed windows are always visible.
158  @see isVisible(), hide(), show()
159  */
160  void setVisible(bool visible);
161 
162  /**
163  Show window.
164  This is the same as calling setVisible(true).
165  @see isVisible(), setVisible(bool)
166  */
167  void show();
168 
169  /**
170  Hide window.
171  This is the same as calling setVisible(false).
172  @see isVisible(), setVisible(bool)
173  */
174  void hide();
175 
176  /**
177  Hide window and notify application of a window close event.
178  The application event-loop will stop when all windows have been closed.
179  For standalone windows only, has no effect if window is embed.
180  @see isEmbed()
181 
182  @note It is possible to hide the window while not stopping the event-loop.
183  A closed window is always hidden, but the reverse is not always true.
184  */
185  void close();
186 
187  /**
188  Check if this window is resizable (by the user or window manager).
189  @see setResizable
190  */
191  bool isResizable() const noexcept;
192 
193  /**
194  Set window as resizable (by the user or window manager).
195  It is always possible to resize a window programmatically, which is not the same as the user being allowed to it.
196  @note This function does nothing for plugins, where the resizable state is set via macro.
197  @see DISTRHO_UI_USER_RESIZABLE
198  */
199  void setResizable(bool resizable);
200 
201  /**
202  Get width.
203  */
204  uint getWidth() const noexcept;
205 
206  /**
207  Get height.
208  */
209  uint getHeight() const noexcept;
210 
211  /**
212  Get size.
213  */
214  Size<uint> getSize() const noexcept;
215 
216  /**
217  Set width.
218  */
219  void setWidth(uint width);
220 
221  /**
222  Set height.
223  */
224  void setHeight(uint height);
225 
226  /**
227  Set size using @a width and @a height values.
228  */
229  void setSize(uint width, uint height);
230 
231  /**
232  Set size.
233  */
234  void setSize(const Size<uint>& size);
235 
236  /**
237  Get the title of the window previously set with setTitle().
238  */
239  const char* getTitle() const noexcept;
240 
241  /**
242  Set the title of the window, typically displayed in the title bar or in window switchers.
243 
244  This only makes sense for non-embedded windows.
245  */
246  void setTitle(const char* title);
247 
248  /**
249  Check if key repeat events are ignored.
250  */
251  bool isIgnoringKeyRepeat() const noexcept;
252 
253  /**
254  Set to ignore (or not) key repeat events according to @a ignore.
255  */
256  void setIgnoringKeyRepeat(bool ignore) noexcept;
257 
258  /**
259  Add a callback function to be triggered on every idle cycle or on a specific timer frequency.
260  You can add more than one, and remove them at anytime with removeIdleCallback().
261  This can be used to perform some action at a regular interval with relatively low frequency.
262 
263  If providing a timer frequency, there are a few things to note:
264  1. There is a platform-specific limit to the number of supported timers, and overhead associated with each,
265  so you should create only a few timers and perform several tasks in one if necessary.
266  2. This timer frequency is not guaranteed to have a resolution better than 10ms
267  (the maximum timer resolution on Windows) and may be rounded up if it is too short.
268  On X11 and MacOS, a resolution of about 1ms can usually be relied on.
269  */
270  bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0);
271 
272  /**
273  Remove an idle callback previously added via addIdleCallback().
274  */
275  bool removeIdleCallback(IdleCallback* callback);
276 
277  /**
278  Get the application associated with this window.
279  */
280  Application& getApp() const noexcept;
281 
282  /**
283  Get the graphics context associated with this window.
284  GraphicsContext is an empty struct and needs to be casted into a different type in order to be usable,
285  for example GraphicsContext.
286  @see CairoSubWidget, CairoTopLevelWidget
287  */
288  const GraphicsContext& getGraphicsContext() const noexcept;
289 
290  /**
291  Get the "native" window handle.
292  Returned value depends on the platform:
293  - HaikuOS: This is a pointer to a `BView`.
294  - MacOS: This is a pointer to an `NSView*`.
295  - Windows: This is a `HWND`.
296  - Everything else: This is an [X11] `Window`.
297  */
298  uintptr_t getNativeWindowHandle() const noexcept;
299 
300  /**
301  Get the scale factor requested for this window.
302  This is purely informational, and up to developers to choose what to do with it.
303 
304  If you do not want to deal with this yourself,
305  consider using setGeometryConstraints() where you can specify to automatically scale the window contents.
306  @see setGeometryConstraints
307  */
308  double getScaleFactor() const noexcept;
309 
310  /**
311  Grab the keyboard input focus.
312  */
313  void focus();
314 
315 #ifndef DGL_FILE_BROWSER_DISABLED
316  /**
317  Open a file browser dialog with this window as parent.
318  A few options can be specified to setup the dialog.
319 
320  If a path is selected, onFileSelected() will be called with the user chosen path.
321  If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename.
322 
323  This function does not block the event loop.
324  */
325  bool openFileBrowser(const FileBrowserOptions& options);
326 #endif
327 
328  /**
329  Request repaint of this window, for the entire area.
330  */
331  void repaint() noexcept;
332 
333  /**
334  Request partial repaint of this window, with bounds according to @a rect.
335  */
336  void repaint(const Rectangle<uint>& rect) noexcept;
337 
338  /**
339  Run this window as a modal, blocking input events from the parent.
340  Only valid for windows that have been created with another window as parent (as passed in the constructor).
341  Can optionally block-wait, but such option is only available if the application is running as standalone.
342  */
343  void runAsModal(bool blockWait = false);
344 
345  /**
346  Set geometry constraints for the Window when resized by the user, and optionally scale contents automatically.
347  */
348  void setGeometryConstraints(uint minimumWidth,
349  uint minimumHeight,
350  bool keepAspectRatio = false,
351  bool automaticallyScale = false);
352 
353  /** DEPRECATED Use isIgnoringKeyRepeat(). */
354  DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()")
355  inline bool getIgnoringKeyRepeat() const noexcept { return isIgnoringKeyRepeat(); }
356 
357  /** DEPRECATED Use getScaleFactor(). */
358  DISTRHO_DEPRECATED_BY("getScaleFactor()")
359  inline double getScaling() const noexcept { return getScaleFactor(); }
360 
361  /** DEPRECATED Use runAsModal(bool). */
362  DISTRHO_DEPRECATED_BY("runAsModal(bool)")
363  inline void exec(bool blockWait = false) { runAsModal(blockWait); }
364 
365  // TESTING, DO NOT USE
366  void leaveContext();
367 
368 protected:
369  /**
370  A function called when the window is attempted to be closed.
371  Returning true closes the window, which is the default behaviour.
372  Override this method and return false to prevent the window from being closed by the user.
373 
374  This method is not used for embed windows, and not even made available in DISTRHO_NAMESPACE::UI.
375  For embed windows, closing is handled by the host/parent process and we have no control over it.
376  As such, a close action on embed windows will always succeed and cannot be cancelled.
377  */
378  virtual bool onClose();
379 
380  /**
381  A function called when the window gains or loses the keyboard focus.
382  The default implementation does nothing.
383  */
384  virtual void onFocus(bool focus, CrossingMode mode);
385 
386  /**
387  A function called when the window is resized.
388  If there is a top-level widget associated with this window, its size will be set right after this function.
389  The default implementation sets up drawing context where necessary.
390  */
391  virtual void onReshape(uint width, uint height);
392 
393  /**
394  A function called when scale factor requested for this window changes.
395  The default implementation does nothing.
396  WARNING function needs a proper name
397  */
398  virtual void onScaleFactorChanged(double scaleFactor);
399 
400 #ifndef DGL_FILE_BROWSER_DISABLED
401  /**
402  A function called when a path is selected by the user, as triggered by openFileBrowser().
403  This action happens after the user confirms the action, so the file browser dialog will be closed at this point.
404  The default implementation does nothing.
405  */
406  virtual void onFileSelected(const char* filename);
407 
408  /** DEPRECATED Use onFileSelected(). */
409  DISTRHO_DEPRECATED_BY("onFileSelected(const char*)")
410  inline virtual void fileBrowserSelected(const char* filename) { return onFileSelected(filename); }
411 #endif
412 
413 private:
414  struct PrivateData;
415  PrivateData* const pData;
416  friend class Application;
417  friend class TopLevelWidget;
418 
419  DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window);
420 };
421 
422 // -----------------------------------------------------------------------
423 
424 END_NAMESPACE_DGL
425 
426 /* TODO
427  * add eventcrossing/enter-leave event
428  */
429 #if 0
430 protected:
431  bool handlePluginKeyboard(const bool press, const uint key);
432  bool handlePluginSpecial(const bool press, const Key key);
433 #endif
434 
435 // -----------------------------------------------------------------------
436 
437 #endif // DGL_WINDOW_HPP_INCLUDED
Window::runAsModal
void runAsModal(bool blockWait=false)
Window::isResizable
bool isResizable() const noexcept
Window::FileBrowserOptions::title
const char * title
Definition: Window.hpp:72
Window::fileBrowserSelected
virtual void fileBrowserSelected(const char *filename)
Definition: Window.hpp:410
Window::setHeight
void setHeight(uint height)
Window::onFocus
virtual void onFocus(bool focus, CrossingMode mode)
Window::FileBrowserOptions::startDir
const char * startDir
Definition: Window.hpp:70
Window::FileBrowserOptions::width
uint width
Definition: Window.hpp:74
GraphicsContext
Definition: Base.hpp:154
Window::show
void show()
Window::FileBrowserOptions::Buttons
Definition: Window.hpp:82
Window::getNativeWindowHandle
uintptr_t getNativeWindowHandle() const noexcept
Window::isVisible
bool isVisible() const noexcept
Window::FileBrowserOptions::FileBrowserOptions
FileBrowserOptions()
Definition: Window.hpp:98
Window::setTitle
void setTitle(const char *title)
Window::setGeometryConstraints
void setGeometryConstraints(uint minimumWidth, uint minimumHeight, bool keepAspectRatio=false, bool automaticallyScale=false)
Window
Definition: Window.hpp:50
Window::onScaleFactorChanged
virtual void onScaleFactorChanged(double scaleFactor)
Window::FileBrowserOptions::Buttons::listAllFiles
ButtonState listAllFiles
Definition: Window.hpp:84
Window::getTitle
const char * getTitle() const noexcept
Window::getScaleFactor
double getScaleFactor() const noexcept
Window::~Window
virtual ~Window()
Size
Definition: Geometry.hpp:132
Rectangle
Definition: Geometry.hpp:30
Application
Definition: Application.hpp:34
Window::repaint
void repaint() noexcept
Window::getWidth
uint getWidth() const noexcept
Window::onClose
virtual bool onClose()
Window::getGraphicsContext
const GraphicsContext & getGraphicsContext() const noexcept
Window::FileBrowserOptions::height
uint height
Definition: Window.hpp:76
Window::FileBrowserOptions::Buttons::showHidden
ButtonState showHidden
Definition: Window.hpp:86
Window::addIdleCallback
bool addIdleCallback(IdleCallback *callback, uint timerFrequencyInMs=0)
Window::onReshape
virtual void onReshape(uint width, uint height)
Window::setVisible
void setVisible(bool visible)
Window::getIgnoringKeyRepeat
bool getIgnoringKeyRepeat() const noexcept
Definition: Window.hpp:355
Window::setWidth
void setWidth(uint width)
Window::setSize
void setSize(uint width, uint height)
Window::isEmbed
bool isEmbed() const noexcept
Window::openFileBrowser
bool openFileBrowser(const FileBrowserOptions &options)
Window::onFileSelected
virtual void onFileSelected(const char *filename)
Window::Window
Window(Application &app)
Window::FileBrowserOptions
Definition: Window.hpp:58
Window::getApp
Application & getApp() const noexcept
Window::exec
void exec(bool blockWait=false)
Definition: Window.hpp:363
Window::FileBrowserOptions::ButtonState
ButtonState
Definition: Window.hpp:63
Window::removeIdleCallback
bool removeIdleCallback(IdleCallback *callback)
IdleCallback
Definition: Base.hpp:159
Window::FileBrowserOptions::Buttons::showPlaces
ButtonState showPlaces
Definition: Window.hpp:88
Window::getScaling
double getScaling() const noexcept
Definition: Window.hpp:359
Window::getSize
Size< uint > getSize() const noexcept
Window::focus
void focus()
Window::setResizable
void setResizable(bool resizable)
Window::setIgnoringKeyRepeat
void setIgnoringKeyRepeat(bool ignore) noexcept
Window::isIgnoringKeyRepeat
bool isIgnoringKeyRepeat() const noexcept
Window::getHeight
uint getHeight() const noexcept
Window::FileBrowserOptions::Buttons::Buttons
Buttons()
Definition: Window.hpp:91
TopLevelWidget
Definition: TopLevelWidget.hpp:46
Window::close
void close()
Window::hide
void hide()