LV2 Toolkit  1.1.1
 All Classes Namespaces Functions Typedefs Enumerations Enumerator Groups Pages
ui.hpp
1 /****************************************************************************
2 
3  ui.hpp - Wrapper library to make it easier to write LV2 UIs in C++
4 
5  Copyright (C) 2012 Michael Fisher <mfisher31@gmail.com>
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  Boston, MA 02110-1301 USA
21 
22  ****************************************************************************/
23 
24 #ifndef LVTK_LV2_UI_HPP
25 #define LVTK_LV2_UI_HPP
26 
27 #include <cstdlib>
28 #include <cstring>
29 #include <iomanip>
30 #include <iostream>
31 #include <map>
32 
33 #include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
34 
35 #include <lvtk/feature.hpp>
36 #include <lvtk/ext/common.h>
37 #include <lvtk/ext/data_access.hpp>
38 #include <lvtk/ext/instance_access.hpp>
39 
40 #include "private/debug.hpp"
41 #include "private/ui_features.hpp"
42 
43 namespace lvtk
44 {
45 
47  #define widget_cast(w) reinterpret_cast<LV2UI_Widget*> (w)
48 
50  class UIDescList : public std::vector<LV2UI_Descriptor>
51  {
52  public:
53  ~UIDescList();
54  };
55 
59  UIDescList&
60  get_lv2g2g_descriptors();
61 
92  template<class Derived, class Ext1 = end, class Ext2 = end,
93  class Ext3 = end, class Ext4 = end, class Ext5 = end,
94  class Ext6 = end, class Ext7 = end, class Ext8 = end,
95  class Ext9 = end>
96  class UI : public MixinTree<Derived, Ext1, Ext2, Ext3, Ext4, Ext5, Ext6,
97  Ext7, Ext8, Ext9>
98  {
99  public:
100 
104  inline
105  UI()
106  {
107  m_ctrl = s_ctrl;
108  m_wfunc = s_wfunc;
109  m_features = s_features;
110  m_bundle_path = s_bundle_path;
111  s_ctrl = 0;
112  s_wfunc = 0;
113  s_features = 0;
114  s_bundle_path = 0;
115  if (m_features)
116  {
117  FeatureHandlerMap hmap;
118  Derived::map_feature_handlers(hmap);
119  for (const lvtk::Feature* const * iter = m_features;
120  *iter != 0; ++iter)
121  {
122  FeatureHandlerMap::iterator miter;
123  miter = hmap.find((*iter)->URI);
124  if (miter != hmap.end())
125  {
126  miter->second(static_cast<Derived*>(this),
127  (*iter)->data);
128  }
129  }
130  }
131  }
132 
135  inline void
136  port_event(uint32_t port, uint32_t buffer_size, uint32_t format,
137  void const* buffer)
138  {
139  }
140 
147  static int
148  register_class(char const* uri)
149  {
150  LV2UI_Descriptor desc;
151  std::memset(&desc, 0, sizeof(LV2UI_Descriptor));
152  desc.URI = strdup(uri);
153  desc.instantiate = &Derived::create_ui_instance;
154  desc.cleanup = &Derived::delete_ui_instance;
155  desc.port_event = &Derived::_port_event;
156  desc.extension_data = &Derived::extension_data;
157 
158  get_lv2g2g_descriptors().push_back(desc);
159  return get_lv2g2g_descriptors().size() - 1;
160  }
161 
162  protected:
163 
168  inline void
169  write(uint32_t port, uint32_t buffer_size, uint32_t format,
170  void const* buffer)
171  {
172  (*m_wfunc)(m_ctrl, port, buffer_size, format, buffer);
173  }
174 
176  inline void
177  write_control(uint32_t port, float value)
178  {
179  write(port, sizeof(float), 0, &value);
180  }
181 
187  inline Feature const* const *
189  {
190  return m_features;
191  }
192 
194  inline char const*
195  bundle_path() const
196  {
197  return m_bundle_path;
198  }
199 
200  public:
206  inline void*
208  {
209  return m_ctrl;
210  }
211 
212  private:
213 
214  // This is quite ugly but needed to allow these mixins to call
215  // protected functions in the UI class, which we want.
216 #if defined (LVTK_EXTRAS_ENABLED)
217  friend class WriteMIDI<true>::I<Derived>;
218  friend class WriteMIDI<false>::I<Derived>;
219  friend class WriteOSC<true>::I<Derived>;
220  friend class WriteOSC<false>::I<Derived>;
221 #endif
222 
228  static LV2UI_Handle
229  create_ui_instance (LV2UI_Descriptor const* descriptor,
230  char const* plugin_uri, char const* bundle_path,
231  LV2UI_Write_Function write_func, LV2UI_Controller ctrl,
232  LV2UI_Widget* widget, LV2_Feature const* const * features)
233  {
234  /* Copy some data to static variables so the subclasses don't have to
235  bother with it - this is threadsafe since hosts are not allowed
236  to instantiate the same plugin concurrently */
237  s_ctrl = ctrl;
238  s_wfunc = write_func;
239  s_features = features;
240  s_bundle_path = bundle_path;
241 
243  if (LVTK_DEBUG)
244  {
245  std::clog << "[LV2::UI] Creating UI...\n\n"
246  << " Plugin URI: \"" << plugin_uri << "\"\n"
247  << " Bundle path: \"" << bundle_path << "\"\n"
248  << " UI Features:\n";
249  lvtk::Feature const* const * iter;
250  for (iter = features; *iter; ++iter)
251  std::clog << " \"" << (*iter)->URI << "\"\n";
252  }
253 
254  // create the UI object
255  if (LVTK_DEBUG)
256  std::clog << " Creating LV2 Widget..." << std::endl;
257  Derived* ui = new Derived(plugin_uri);
258  *widget = ui->widget();
259 
261  if (ui->check_ok() && *widget != NULL)
262  {
263  return reinterpret_cast<LV2UI_Handle>(ui);
264  }
265 
266  delete ui;
267  return 0;
268  }
269 
275  static void
276  delete_ui_instance(LV2UI_Handle instance)
277  {
278  delete static_cast<Derived*>(instance);
279  }
280 
285  static void
286  _port_event(LV2UI_Handle instance, uint32_t port,
287  uint32_t buffer_size, uint32_t format, void const* buffer)
288  {
289  static_cast<Derived*>(instance)->port_event(port, buffer_size,
290  format, buffer);
291  }
292 
293  void* m_ctrl;
294  LV2UI_Write_Function m_wfunc;
295  lvtk::Feature const* const * m_features;
296  char const* m_bundle_path;
297 
298  static void* s_ctrl;
299  static LV2UI_Write_Function s_wfunc;
300  static lvtk::Feature const* const * s_features;
301  static char const* s_bundle_path;
302 
303  };
304 
305  /* Yes, static variables are messy. */
306  template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
307  class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
308  void* UI<Derived, Ext1, Ext2, Ext3, Ext4, Ext5, Ext6, Ext7, Ext8, Ext9>::s_ctrl =
309  0;
310 
311  template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
312  class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
313  LV2UI_Write_Function UI<Derived, Ext1, Ext2, Ext3, Ext4, Ext5, Ext6,
314  Ext7, Ext8, Ext9>::s_wfunc = 0;
315 
316  template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
317  class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
318  lvtk::Feature const* const * UI<Derived, Ext1, Ext2, Ext3, Ext4, Ext5,
319  Ext6, Ext7, Ext8, Ext9>::s_features = 0;
320 
321  template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
322  class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
323  char const* UI<Derived, Ext1, Ext2, Ext3, Ext4, Ext5, Ext6, Ext7, Ext8,
324  Ext9>::s_bundle_path = 0;
325 
326 }
327 
328 #endif /* LVTK_LV2_UI_HPP */