1 /*
2  * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/>
3  *           (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com>
4  *
5  * This file is part of lsp-plugins
6  * Created on: 20 окт. 2015 г.
7  *
8  * lsp-plugins is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * any later version.
12  *
13  * lsp-plugins is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #ifndef _UI_PLUGIN_UI_H_
23 #define _UI_PLUGIN_UI_H_
24 
25 #include <metadata/metadata.h>
26 
27 #include <data/cvector.h>
28 
29 #include <ui/ws/ws.h>
30 #include <core/io/IInStream.h>
31 #include <core/files/config.h>
32 #include <core/port_data.h>
33 
34 namespace lsp
35 {
36     class plugin_ui: public CtlRegistry
37     {
38         private:
39             plugin_ui &operator = (const plugin_ui &);
40 
41         protected:
42             typedef struct preset_t
43             {
44                 char       *name;
45                 char       *path;
46                 LSPWidget  *item;
47             } preset_t;
48 
49             class ConfigHandler: public config::IConfigHandler
50             {
51                 private:
52                     plugin_ui          *pUI;
53                     cvector<CtlPort>   &hPorts;
54                     KVTStorage         *pKVT;
55                     cvector<char>       vNotify;
56                     bool                bPreset;
57                     io::Path           *pBasePath;
58 
59                 protected:
60                     void add_notification(const char *id);
61 
62                 public:
ConfigHandler(plugin_ui * ui,cvector<CtlPort> & ports,KVTStorage * kvt,bool preset,io::Path * base)63                     explicit ConfigHandler(plugin_ui *ui, cvector<CtlPort> &ports,
64                             KVTStorage *kvt, bool preset, io::Path *base
65                     ):
66                         pUI(ui), hPorts(ports), pKVT(kvt), bPreset(preset), pBasePath(base) {}
67                     virtual ~ConfigHandler();
68 
69                 public:
70                     virtual status_t handle_parameter(const char *name, const char *value, size_t flags);
71 
72                     virtual status_t handle_kvt_parameter(const char *name, const kvt_param_t *param, size_t flags);
73 
74                     void notify_all();
75             };
76 
77             class ConfigSource: public config::IConfigSource
78             {
79                 private:
80                     plugin_ui      *pUI;
81                     cvector<CtlPort> &hPorts;
82                     LSPString      *pComment;
83                     KVTIterator    *pIter;
84                     size_t          nPortID;
85                     io::Path       *pBasePath;
86 
87                 public:
ConfigSource(plugin_ui * ui,cvector<CtlPort> & ports,KVTStorage * kvt,LSPString * comment,io::Path * base)88                     explicit ConfigSource(plugin_ui *ui, cvector<CtlPort> &ports,
89                             KVTStorage *kvt, LSPString *comment, io::Path *base
90                         ):
91                         pUI(ui), hPorts(ports), pComment(comment), nPortID(0) {
92                         pIter       = (kvt != NULL) ? kvt->enum_all() : NULL;
93                         pBasePath   = base;
94                     }
95 
96                 public:
97                     virtual status_t get_head_comment(LSPString *comment);
98 
99                     virtual status_t get_parameter(LSPString *name, LSPString *value, LSPString *comment, int *flags);
100             };
101 
102             class ConfigSink: public LSPTextDataSink
103             {
104                 private:
105                     plugin_ui      *pUI;
106 
107                 public:
ConfigSink(plugin_ui * ui)108                     explicit ConfigSink(plugin_ui *ui): pUI(ui) {}
109                     virtual ~ConfigSink();
110 
111                     void unbind();
112 
113                 public:
114                     virtual status_t    on_complete(status_t code, const LSPString *data);
115             };
116 
117         protected:
118             const plugin_metadata_t    *pMetadata;
119             IUIWrapper                 *pWrapper;
120             LSPWindow                  *pRoot;
121             CtlPluginWindow            *pRootCtl;
122             void                       *pRootWidget;
123 
124             LSPDisplay                  sDisplay;
125 
126             cvector<CtlPort>            vPorts;
127             cvector<CtlPort>            vCustomPorts;
128             cvector<CtlPort>            vSortedPorts;
129             cvector<CtlPort>            vConfigPorts;
130             cvector<CtlValuePort>       vTimePorts;
131             cvector<LSPWidget>          vWidgets;
132             cvector<CtlSwitchedPort>    vSwitched;
133             cvector<CtlPortAlias>       vAliases;
134             cvector<CtlKvtListener>     vKvtListeners;
135 
136             cstorage<preset_t>          vPresets;
137             ConfigSink                 *pConfigSink;
138 
139         protected:
140             static const port_t         vConfigMetadata[];
141             static const port_t         vTimeMetadata[];
142 
143         protected:
144             size_t          rebuild_sorted_ports();
145             CtlWidget      *build_widget(widget_ctl_t w_class);
146             io::File       *open_config_file(bool write);
147             bool            apply_changes(const char *key, const char *value, cvector<CtlPort> &ports, bool preset, const io::Path *base);
148             status_t        scan_presets();
149             void            build_config_header(LSPString &c);
150             void            destroy_presets();
151             status_t        paste_from_clipboard(const LSPString *data);
152 
153             static status_t slot_preset_select(LSPWidget *sender, void *ptr, void *data);
154 
155         public:
156             explicit plugin_ui(const plugin_metadata_t *mdata, void *root_widget);
157             virtual ~plugin_ui();
158 
159             virtual void destroy();
160 
161         public:
metadata()162             inline const plugin_metadata_t *metadata() const { return pMetadata; };
wrapper()163             inline IUIWrapper *wrapper() { return pWrapper; };
164 
165         public:
166             CtlWidget      *create_widget(const char *w_ctl);
167             CtlWidget      *create_widget(widget_ctl_t w_class);
168 
169         public:
170             /** Initialize UI
171              *
172              * @param root_widget root widget to use as a base
173              * @param wrapper plugin wrapper
174              * @param argc number of arguments
175              * @param argv list of arguments
176              * @return status of operation
177              */
178             virtual status_t    init(IUIWrapper *wrapper, int argc, const char **argv);
179 
180             /**
181              * Build UI from the XML schema
182              * @return status of operation
183              */
184             virtual status_t    build();
185 
186             /** Method executed when the time position of plugin was updated
187              *
188              */
189             void position_updated(const position_t *pos);
190 
191             /** Add plugin port to UI
192              *
193              * @param port UI port to communicate with plugin
194              * @return status of operation
195              */
196             status_t add_port(CtlPort *port);
197 
198             /** Add custom port to UI
199              *
200              * @param port custom UI port
201              * @return status of operation
202              */
203             status_t add_custom_port(CtlPort *port);
204 
205             /** Export settings of the UI to the file
206              *
207              * @param filename file name
208              * @param relative use relative paths
209              * @return status of operation
210              */
211             status_t export_settings(const char *filename, bool relative);
212 
213             /** Import settings of the UI from the file
214              *
215              * @param filename file name
216              * @param preset indicator that the source is preset
217              * @return status of operation
218              */
219             status_t import_settings(const char *filename, bool preset);
220 
221             /**
222              * Export settings to clipboard
223              * @return status of operation
224              */
225             status_t export_settings_to_clipboard();
226 
227             /**
228              * Import settings from clipboard
229              * @return status of operation
230              */
231             status_t import_settings_from_clipboard();
232 
233             /** Save global configuration file
234              *
235              * @return status of operation
236              */
237             status_t save_global_config();
238 
239             /** Load global configuration file
240              *
241              * @return status of operation
242              */
243             status_t load_global_config();
244 
245             /** Get INTERNAL port by name
246              *
247              * @param name port name
248              * @return internal port
249              */
250             CtlPort *port(const char *name);
251 
252             /**
253              * Get port by index
254              * @param idx index of the port
255              * @return internal port by index
256              */
257             CtlPort *port_by_index(size_t idx);
258 
259             /** Get port count
260              *
261              * @return number of ports
262              */
ports_count()263             inline size_t ports_count()
264             {
265                 return vPorts.size();
266             }
267 
268             /** Show UI
269              *
270              */
show()271             inline void show()
272             {
273                 if (pRoot != NULL)
274                     pRoot->show();
275             }
276 
277             /** Hide UI
278              *
279              */
hide()280             inline void hide()
281             {
282                 if (pRoot != NULL)
283                     pRoot->hide();
284             }
285 
286             /** Get width of main plugin window
287              *
288              * @return width of main plugin window
289              */
width()290             inline size_t width()   { return (pRoot != NULL) ? pRoot->width() : 0; }
291 
292             /** Get height of main plugin window
293              *
294              * @return height of main plugin window
295              */
height()296             inline size_t height()  { return (pRoot != NULL) ? pRoot->height() : 0; }
297 
298             /** Get Display
299              *
300              * @return display
301              */
display()302             inline LSPDisplay *display()    { return &sDisplay; };
303 
304             /** Main UI function
305              *
306              * @return main function
307              */
main()308             inline status_t main()          { return sDisplay.main(); };
309 
310             /** Main iteration
311              *
312              * @return main iteration
313              */
main_iteration()314             inline status_t main_iteration() { return sDisplay.main_iteration(); }
315 
316             /**
317              * Synchronize state of meta ports
318              */
319             void sync_meta_ports();
320 
321             /** Return root window
322              *
323              * @return root window (if exists)
324              */
root_window()325             inline LSPWindow *root_window() { return pRoot; }
326 
327             /**
328              * Set title of the main window
329              * @param title title of the main window
330              */
331             void set_title(const char *title);
332 
333             /**
334              * Notify the write of the KVT parameter
335              * @param storage KVT storage
336              * @param id kvt parameter identifier
337              * @param value KVT parameter value
338              */
339             virtual void kvt_write(KVTStorage *storage, const char *id, const kvt_param_t *value);
340 
341             /**
342              * Lock the KVT storage
343              * @return pointer to KVT storage or NULL
344              */
345             virtual KVTStorage *kvt_lock();
346 
347             /**
348              * Try to lock the KVT storage
349              * @return pointer to KVT storage or NULL if not locked/not supported
350              */
351             virtual KVTStorage *kvt_trylock();
352 
353             /**
354              * Release the KVT storage
355              */
356             virtual void kvt_release();
357 
358             /**
359              * Add KVT listener
360              * @param listener listener to add
361              * @return status of operation
362              */
363             virtual status_t add_kvt_listener(CtlKvtListener *listener);
364 
365             /**
366              * Request state dump
367              */
368             void request_state_dump();
369     };
370 
371 } /* namespace lsp */
372 
373 #endif /* _UI_PLUGIN_UI_H_ */
374