From e829764081df5b107b166c2420cb89bd12ecf3a2 Mon Sep 17 00:00:00 2001 From: tytan652 Date: Wed, 30 Mar 2022 21:03:27 +0200 Subject: [PATCH] Add RFC: Switch to Advanced Docking System --- .../0047-switch-to-advanced-docking-system.md | 264 ++++++++++++++++++ .../legacy_dock.png | Bin 0 -> 9367 bytes .../linux_native_floating_dock_titlebar.png | Bin 0 -> 9460 bytes .../linux_qwidget_floating_dock_titlebar.png | Bin 0 -> 9238 bytes 4 files changed, 264 insertions(+) create mode 100644 text/0047-switch-to-advanced-docking-system.md create mode 100644 text/0047-switch-to-advanced-docking-system/legacy_dock.png create mode 100644 text/0047-switch-to-advanced-docking-system/linux_native_floating_dock_titlebar.png create mode 100644 text/0047-switch-to-advanced-docking-system/linux_qwidget_floating_dock_titlebar.png diff --git a/text/0047-switch-to-advanced-docking-system.md b/text/0047-switch-to-advanced-docking-system.md new file mode 100644 index 0000000..b5bdb51 --- /dev/null +++ b/text/0047-switch-to-advanced-docking-system.md @@ -0,0 +1,264 @@ +# Summary + +- Switch main dock system to [ADS][1] +- Make ADS dock state per profile +- Allow the user to switch between pre-made layouts + - Plugins could register their own + - Users could save their own +- Dock added by plugins with the old method are added as "*Legacy dock*" + +Note: The "central widget" design is kept. + +# Motivation + +Provide a better dock system to end-users. + +# Design +**DISCLAIMER**: I kept the "central widget" design, switching to a non-"central widget" one is not part of this RFC. + +## Main window dock separation +To make OBS Studio compatible with ADS, Controls, Transitions, Mixer, Sources, Scenes docks need to be separated from the main window. + +And the central widget of main window should also be separated as well. + +So the central widget and docks will be separated as widget and then inserted in ADS dock, and the docks inside the dock manager. + +The Main window heavily rely on some UI element from those docks, to resolve that when really required OBSBasic will be set as a friend class of the widget. + +Each widget class will be put as a friend class in OBSBasic to allow access to private slot and avoid moving them as public. + +### Controls widget +*Future ADS Controls dock widget* + +Some hotkeys and pause functions rely on UI buttons, so OBS Basic will be added as friend class to allow access to those to OBSBasic. + +> In my [WIP implementation][2], many signals are added to OBSBasic to interract with widget UI through slots. + +### Transistions widget +*Future ADS Transitions dock widget* + +While the transitions duration spinbox can be set up to change an attribute from OBSBasic. The transitions combobox was used to store transtions. + +So for the time being, this combobox will accessed by OBSBasic by making it a friend class of the widget. + +### Mixer widget +*Future ADS Mixer dock widget* + +Easily separable, no need to set OBSBasic as a friend class of this widget. + +### Sources widget +*Future ADS Sources dock widget* + +OBSBasic heavily rely on the SourceTree from the widget, so for now OBSBasic will access it by being a friend class of the widget. + +### Scenes widget +*Future ADS Scenes dock widget* + +OBSBasic heavily rely on the SceneTree from the widget, so for now OBSBasic will access it by being a friend class of the widget. + +### Central widget +*Future ADS Central dock widget* + +***Still need to work on the it and the text, because it's heavily tied to OBSBasic.*** + +## ADS +The Advanced Docking System, require to add a Dock Manager in the main window and then add the central widget and then add other docks. + +Some work on themes CSS will be required. + +### Floating docks titlebar on X11 +On X11, ADS provide two type of titlebar for floating docks: + +- Native + +[![Native titlebar under GNOME](./0047-switch-to-advanced-docking-system/linux_native_floating_dock_titlebar.png)]() + +- QWidget based (WIP CSS) + +[![QWidget titlebar](./0047-switch-to-advanced-docking-system/linux_qwidget_floating_dock_titlebar.png)]() + +The QWidget one is used by default when using KWin based Desktop Environement like Plasma. And this titlebar requires some CSS in the themes to match it. + +So the QWidget based titlebar usage will be enforced thanks to a flag for the Dock Manager to "force" theme makers to theme this bar, and not just ignore it because it's only "under Plasma X11". + +### Dock state +*The per profile dock state feature is not taken into account.* + +In the global config (`global.ini`). +- `"dockState"` is kept for for backward compatiblity and no longer overwitten. It will be used if the following state is not present. +- `"windowState"` is the state of the main window, since it does not store only the state of legacy docks. +- `"advDockState"` is the state of the dock manager which contain only the states of any ADS dock. + +Service integrations only save `"advDockProfile"` + +ADS dock state is compressed by default but behind the scene it's XML. + +### OBSAdvDock +OBSAdvDock is a class which inherit `ads::CDockWidget` class. + +This class has a constructor which require a QWidget and setup some things arround the widget and set some connections. + +It adds a warning message when closing a dock from a close dock button. + +It allows to reset a dock position after a UI reset or a layout change with a possibility to reset the size if set beforehand. + +### Custom Browser docks and BrowserAdvDock +The custom browser docks feature is modified to use BrowserAdvDock which inherit OBSAdvDock. + +Those docks are stored in the dock manager and their names is stored in a QStringList for browser docks to be able to get the dock from the manager to modify it like changing the URL. + +Each of those browser dock is named `extraBrowser_$UUID` where `$UUID` is replaced by the dock UUID to have a really unique name. + +### Service integration docks + +Like custom browser docks, those integration are modified to use BrowserAdvDock. But their names is stored in the QStringList for plugins extra docks. + +Those docks are named `obs-$SERVICE_$DOCK_NAME` where `$SERVICE` is the service name in lowercase and `$DOCK_NAME` the name of the dock. + +`"dockState"` will be imported from the integration config if `"windowState"` is not present. + +### Reset UI action +1. Legacy dock are hidden +2. The default state written in XML is applied +3. Each not shown OBSAdvDock/BrowserAdvDock dock have its position and size reseted. + +## Legacy dock +The frontend API method `obs_frontend_add_dock()` is put in deprecation. + +And dock added through this method are added to a sub-menu named `Legacy dock` of the Dock menu. + +[![Legacy dock menu](./0047-switch-to-advanced-docking-system/legacy_dock.png)]() + +When openning a legacy dock, a message will appear explaining that those docks will not meld wery well with "new" docks. + +The state of those are saved through `"windowState"` global config. + +## Per profile dock state +Move the `"advDockState"` from global config to the profile. `"windowState"` is kept global. + +If a release happen between the switch to ADS and this feature, import the one from the integration service if the profile has one set up. + +## Layouts management +Add the feature, to switch between registered/saved dock layouts: +- Though a sub-menu in the dock menu +- Through a hotkey +- Through the frontend API + +OBS Studio could provide layouts, the default count as one. + +Plugins could also register their own XML layouts through the frontend API. + +Users could be able to save their own layouts. Those layouts will have their name prefixed with`user_` to avoid name conflicts. + +Note: ADS perspective feature is not directly used because it relies heavily on QSettings. + +## Frontend API +Like said earlier, the method `obs_frontend_add_dock()` is put in deprecation. + +All add/remove methods related to ADS requiring a name will require the plugin module to be able to prefix the given name with the module name to avoid conflicts. + +### Add a dock +**WIP**: Need some thought about setting a default size, maybe based on the QWidget size. +```c++ +/* takes QWidget */ +#define obs_frontend_add_adv_dock(title, unique_name, dock) \ + obs_frontend_add_module_adv_dock(obs_current_module(), title, \ + unique_name, widget) +EXPORT void obs_frontend_add_module_adv_dock(obs_module_t *module, + const char *title, + const char *unique_name, + void *widget); +``` + +This allow to add a OBSAdvDock with the given QWidget. Those docks are stored in the Dock Manager and their names is stored in the QStringList for plugins extra docks. + +### Remove a dock +```c++ +#define obs_frontend_remove_adv_dock(unique_name) \ + obs_frontend_add_module_adv_dock(obs_current_module(), unique_name) +EXPORT void obs_frontend_remove_module_adv_dock(obs_module_t *module, + const char *unique_name); +``` + +This allow the plugin to remove a dock added earlier. + +### Add a browser dock +**WIP** + +This allow the plugin to a dock with a QCefWidget as widget. + +### Add a dock layouts +**WIP** + +This allow the plugin to add a dock layouts to the UI. + +### Get a list of docks layouts +**WIP** + +This allow the plugin to get a list of registered dock layouts from the UI. + +### Set a registered dock layout +**WIP** + +This allow the plugin to set a registered dock layouts to the UI, the asked name should come directly from the get list method. + +### Remove a dock layouts +**WIP** + +This allow the plugin to remove a dock layouts from the UI. + +### Add a entirely custom dock +```c++ +/* takes ads::CDockWidget */ +#define obs_frontend_add_custom_adv_dock(unique_name, dock) \ + obs_frontend_add_module_custom_adv_dock(obs_current_module(), \ + unique_name, dock) +EXPORT void obs_frontend_add_module_custom_adv_dock(obs_module_t *module, + const char *unique_name, + void *dock); +``` + +Some plugin like [Sources Dock][6], do not add their docks to the Dock menu. + +So this method allow to do this but requires the plugin to be link against ADS library. + +And the dock will not have OBSAdvDock features. + +`obs_frontend_remove_adv_dock()` can be used to remove the reference stored in the Dock Manager. Because their names is stored in the QStringList for plugins custom extra docks. + +### Get the XML behind a registered dock layout +**WIP** +*Method meant to allow a Dock Layout editor tool to exist* + +### Get the XML of the actual dock state +**WIP** +*Method meant to allow a Dock Layout editor tool to exist* + +### Events addition +- An event before the startup restore dock state and `OBS_FRONTEND_EVENT_FINISHED_LOADING` to allow plugins to load their docks before the restore or redo a restore if the number of extra docks has changed. This event could possibly be emitted when profile is changed before restoring profile dock state and `OBS_FRONTEND_EVENT_PROFILE_CHANGED`. + +- An event when the a dock layout is applied (reset or not) to allow plugins to reset the positions of their customs docks, if they want to. + +## About making dock states future proof +By default generated state are version 0. If one day we make a breaking change like remove the notion of central widget and so change the version. + +We could take the saved `"advDockState"` and uncompress to edit the XML, to make it compatible with the change. + +# Drawbacks +We can't convert old `"dockState"` to the new dock system. + +# Additional Information +We may require to make some changes to allow ADS to be built on FreeBSD and submit the required changes to upstream. **I'm just waiting for a build guide for OBS Studio on FreeBSD.** + +My WIP branches: +- [Main window dock separation][2] +- [Switch to ADS][3] +- [Frontend API to add ADS dock][4] +- [Frontend API to add custom ADS dock][5] + +[1]: https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System +[2]: https://github.com/tytan652/obs-studio/tree/main_win_separation +[3]: https://github.com/tytan652/obs-studio/tree/advanced_docking +[4]: https://github.com/tytan652/obs-studio/tree/ads_frontend_api +[5]: https://github.com/tytan652/obs-studio/tree/add_custom_dock +[6]: https://obsproject.com/forum/resources/source-dock.1317/ \ No newline at end of file diff --git a/text/0047-switch-to-advanced-docking-system/legacy_dock.png b/text/0047-switch-to-advanced-docking-system/legacy_dock.png new file mode 100644 index 0000000000000000000000000000000000000000..41392765ea7ece37146bd7e98ea9fc98228b100c GIT binary patch literal 9367 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 literal 0 HcmV?d00001 diff --git a/text/0047-switch-to-advanced-docking-system/linux_native_floating_dock_titlebar.png b/text/0047-switch-to-advanced-docking-system/linux_native_floating_dock_titlebar.png new file mode 100644 index 0000000000000000000000000000000000000000..54473949fcfa4d6d6ded6383bf259b4e6859b486 GIT binary patch literal 9460 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 xpFoXuK1ZynpCeURp(}6!!k}{{rqQ6Hx#F literal 0 HcmV?d00001 diff --git a/text/0047-switch-to-advanced-docking-system/linux_qwidget_floating_dock_titlebar.png b/text/0047-switch-to-advanced-docking-system/linux_qwidget_floating_dock_titlebar.png new file mode 100644 index 0000000000000000000000000000000000000000..ca31c879dbf02ff4ddf398db1c629d053c0479e0 GIT binary patch literal 9238 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