1 /*
2  * dock.cc
3  * Copyright 2020 John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions, and the following disclaimer in the documentation
13  *    provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include "dock.h"
21 #include "libaudqt-internal.h"
22 #include "libaudqt.h"
23 
24 #include <assert.h>
25 
26 #include <libaudcore/audstrings.h>
27 #include <libaudcore/hook.h>
28 #include <libaudcore/plugins.h>
29 #include <libaudcore/runtime.h>
30 
31 namespace audqt
32 {
33 
34 class SimpleDockItem : public DockItem
35 {
36 public:
SimpleDockItem(const char * id,const char * name,QWidget * widget)37     SimpleDockItem(const char * id, const char * name, QWidget * widget)
38         : DockItem(id, name, widget)
39     {
40     }
41 
user_close()42     void user_close() override { dock_hide_simple(id()); }
43 
44     static SimpleDockItem * lookup(const char * id);
45 };
46 
47 class PluginItem : public DockItem
48 {
49 public:
PluginItem(PluginHandle * plugin,QWidget * widget)50     PluginItem(PluginHandle * plugin, QWidget * widget)
51         : DockItem(aud_plugin_get_basename(plugin), aud_plugin_get_name(plugin),
52                    widget),
53           m_plugin(plugin)
54     {
55     }
56 
grab_focus()57     void grab_focus() override
58     {
59         DockItem::grab_focus();
60         // invoke plugin-specific focus handling
61         aud_plugin_send_message(m_plugin, "grab focus", nullptr, 0);
62     }
63 
64     // explicitly closing the widget disables the plugin
user_close()65     void user_close() override { aud_plugin_enable(m_plugin, false); }
66 
67     static PluginItem * lookup(PluginHandle * plugin);
68 
69 private:
70     PluginHandle * m_plugin;
71 };
72 
73 static DockHost * s_host = nullptr;
74 static Index<DockItem *> s_items;
75 
DockItem(const char * id,const char * name,QWidget * widget)76 EXPORT DockItem::DockItem(const char * id, const char * name, QWidget * widget)
77     : m_id(id), m_name(name), m_widget(widget)
78 {
79     assert(s_host);
80     s_host->add_dock_item(this);
81     s_items.append(this);
82 }
83 
~DockItem()84 EXPORT DockItem::~DockItem()
85 {
86     assert(s_host);
87     s_items.remove(s_items.find(this), 1);
88     s_host->remove_dock_item(this);
89     delete m_widget;
90 }
91 
grab_focus()92 EXPORT void DockItem::grab_focus()
93 {
94     assert(s_host);
95     s_host->focus_dock_item(this);
96 }
97 
find_by_plugin(PluginHandle * plugin)98 EXPORT DockItem * DockItem::find_by_plugin(PluginHandle * plugin)
99 {
100     return PluginItem::lookup(plugin);
101 }
102 
lookup(const char * id)103 SimpleDockItem * SimpleDockItem::lookup(const char * id)
104 {
105     for (auto item_ : s_items)
106     {
107         auto item = dynamic_cast<SimpleDockItem *>(item_);
108         if (item && !strcmp(item->id(), id))
109             return item;
110     }
111 
112     return nullptr;
113 }
114 
dock_show_simple(const char * id,const char * name,QWidget * create ())115 void dock_show_simple(const char * id, const char * name, QWidget * create())
116 {
117     if (!s_host)
118     {
119         AUDWARN("No UI can dock the widget %s\n", id);
120         return;
121     }
122 
123     auto cfg_key = str_concat({id, "_visible"});
124     aud_set_bool("audqt", cfg_key, true);
125 
126     auto item = SimpleDockItem::lookup(id);
127     if (!item)
128         item = new SimpleDockItem(id, name, create());
129 
130     item->grab_focus();
131 }
132 
dock_hide_simple(const char * id)133 void dock_hide_simple(const char * id)
134 {
135     auto cfg_key = str_concat({id, "_visible"});
136     aud_set_bool("audqt", cfg_key, false);
137 
138     delete SimpleDockItem::lookup(id);
139 }
140 
lookup(PluginHandle * plugin)141 PluginItem * PluginItem::lookup(PluginHandle * plugin)
142 {
143     for (auto item_ : s_items)
144     {
145         auto item = dynamic_cast<PluginItem *>(item_);
146         if (item && item->m_plugin == plugin)
147             return item;
148     }
149 
150     return nullptr;
151 }
152 
add_dock_plugin(void * plugin_,void *)153 static void add_dock_plugin(void * plugin_, void *)
154 {
155     auto plugin = (PluginHandle *)plugin_;
156     auto widget = (QWidget *)aud_plugin_get_qt_widget(plugin);
157     if (widget)
158         new PluginItem(plugin, widget);
159 }
160 
remove_dock_plugin(void * plugin_,void *)161 static void remove_dock_plugin(void * plugin_, void *)
162 {
163     auto plugin = (PluginHandle *)plugin_;
164     delete PluginItem::lookup(plugin);
165 }
166 
register_dock_host(DockHost * host)167 EXPORT void register_dock_host(DockHost * host)
168 {
169     assert(!s_host);
170     s_host = host;
171 
172     if (aud_get_bool("audqt", "eq_presets_visible"))
173         eq_presets_show();
174     if (aud_get_bool("audqt", "equalizer_visible"))
175         equalizer_show();
176     if (aud_get_bool("audqt", "queue_manager_visible"))
177         queue_manager_show();
178 
179     for (PluginHandle * plugin : aud_plugin_list(PluginType::General))
180     {
181         if (aud_plugin_get_enabled(plugin))
182             add_dock_plugin(plugin, nullptr);
183     }
184 
185     for (PluginHandle * plugin : aud_plugin_list(PluginType::Vis))
186     {
187         if (aud_plugin_get_enabled(plugin))
188             add_dock_plugin(plugin, nullptr);
189     }
190 
191     hook_associate("dock plugin enabled", add_dock_plugin, nullptr);
192     hook_associate("dock plugin disabled", remove_dock_plugin, nullptr);
193 }
194 
unregister_dock_host()195 EXPORT void unregister_dock_host()
196 {
197     assert(s_host);
198 
199     hook_dissociate("dock plugin enabled", add_dock_plugin);
200     hook_dissociate("dock plugin disabled", remove_dock_plugin);
201 
202     while (s_items.len() > 0)
203         delete s_items[0];
204 
205     s_host = nullptr;
206 }
207 
208 } // namespace audqt
209