• Main Page
  • Modules
  • Classes
  • Files
  • File List

libraries/lv2gui/lv2gui.hpp

00001 /****************************************************************************
00002     
00003     lv2gui.hpp - Wrapper library to make it easier to write LV2 GUIs in C++
00004     
00005     Copyright (C) 2006-2008 Lars Luthman <lars.luthman@gmail.com>
00006     Modified by Dave Robillard, 2008 (URI map mixin)
00007     
00008     This program is free software; you can redistribute it and/or modify
00009     it under the terms of the GNU General Public License as published by
00010     the Free Software Foundation; either version 3 of the License, or
00011     (at your option) any later version.
00012     
00013     This program is distributed in the hope that it will be useful,
00014     but WITHOUT ANY WARRANTY; without even the implied warranty of
00015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016     GNU General Public License for more details.
00017     
00018     You should have received a copy of the GNU General Public License
00019     along with this program; if not, write to the Free Software
00020     Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021     Boston, MA  02110-1301  USA
00022 
00023 ****************************************************************************/
00024 
00025 #ifndef LV2GUI_HPP
00026 #define LV2GUI_HPP
00027 
00028 #include <cstdlib>
00029 #include <cstring>
00030 #include <map>
00031 
00032 #include <gtkmm/box.h>
00033 #include <gtkmm/main.h>
00034 #include <gtkmm/widget.h>
00035 
00036 #include <lv2_ui.h>
00037 #include <lv2_ui_presets.h>
00038 #include <lv2_uri_map.h>
00039 #include <lv2_event_helpers.h>
00040 #include <lv2_osc.h>
00041 #include <lv2types.hpp>
00042 
00043 
00044 namespace LV2 {
00045 
00046   
00049   typedef std::vector<LV2UI_Descriptor*> GUIDescList;
00050     
00051   
00055   GUIDescList& get_lv2g2g_descriptors();
00056   
00057   
00104   template <bool Required = true>
00105   struct NoUserResize {
00106     
00111     template <class Derived> struct I : public Extension<Required> {
00112       
00114       static void map_feature_handlers(FeatureHandlerMap& hmap) {
00115         hmap["http://ll-plugins.nongnu.org/lv2/dev/ui#noUserResize"] = 
00116           &I<Derived>::handle_feature;
00117       }
00118       
00120       static void handle_feature(void* instance, void* data) { 
00121         Derived* d = reinterpret_cast<Derived*>(instance);
00122         I<Derived>* e = static_cast<I<Derived>*>(d);
00123         e->m_ok = true;
00124       }
00125       
00126     };
00127     
00128   };
00129 
00130 
00140   template <bool Required = true>
00141   struct FixedSize {
00142     
00147     template <class Derived> struct I : public Extension<Required> {
00148       
00150       static void map_feature_handlers(FeatureHandlerMap& hmap) {
00151         hmap["http://ll-plugins.nongnu.org/lv2/dev/ui#fixedSize"] = 
00152           &I<Derived>::handle_feature;
00153       }
00154       
00156       static void handle_feature(void* instance, void* data) {
00157         Derived* d = reinterpret_cast<Derived*>(instance);
00158         I<Derived>* e = static_cast<I<Derived>*>(d);
00159         e->m_ok = true;
00160       }
00161     
00162     };
00163     
00164   };
00165 
00166 
00175   template <bool Required = true>
00176   struct Presets {
00177     
00182     template <class Derived> struct I : public Extension<Required> {
00183       
00185       I() : m_hdesc(0), m_host_support(false) { }
00186         
00188         static void map_feature_handlers(FeatureHandlerMap& hmap) {
00189           hmap[LV2_UI_PRESETS_URI] = &I<Derived>::handle_feature;
00190         }
00191         
00193         static void handle_feature(void* instance, void* data) {
00194           Derived* d = reinterpret_cast<Derived*>(instance);
00195           I<Derived>* e = static_cast<I<Derived>*>(d);
00196           e->m_hdesc = static_cast<LV2UI_Presets_Feature*>(data);
00197           e->m_ok = (e->m_hdesc != 0);
00198           e->m_host_support = (e->m_hdesc != 0);
00199         }
00200         
00201         
00207         void preset_added(uint32_t    number, 
00208                            char const* name) {
00209           
00210         }
00211         
00216         void preset_removed(uint32_t number) {
00217           
00218         }
00219         
00223         void presets_cleared() {
00224           
00225         }
00226         
00233         void current_preset_changed(uint32_t number) {
00234           
00235         }
00236         
00240         static void const* extension_data(char const* uri) {
00241           static LV2UI_Presets_GDesc desc = { &_preset_added,
00242                                               &_preset_removed,
00243                                               &_presets_cleared,
00244                                               &_current_preset_changed };
00245           if (!std::strcmp(uri, LV2_UI_PRESETS_URI))
00246             return &desc;
00247           return 0;
00248         }
00249         
00250     protected:
00251         
00254         void change_preset(uint32_t preset) {
00255           if (m_hdesc)
00256             m_hdesc->change_preset(static_cast<Derived*>(this)->controller(), 
00257                                    preset);
00258         }
00259         
00263         void save_preset(uint32_t preset, char const* name) {
00264           if (m_hdesc)
00265             m_hdesc->save_preset(static_cast<Derived*>(this)->controller(), 
00266                                  preset, name);
00267         }
00268       
00271         bool host_supports_presets() const {
00272           return m_host_support;
00273         }
00274         
00275     private:
00276         
00277         static void _preset_added(LV2UI_Handle gui, 
00278                                    uint32_t     number, 
00279                                    char const*  name) {
00280           static_cast<Derived*>(gui)->preset_added(number, name);
00281         }
00282         
00283         static void _preset_removed(LV2UI_Handle gui, 
00284                                      uint32_t     number) {
00285           static_cast<Derived*>(gui)->preset_removed(number);
00286         }
00287         
00288         static void _presets_cleared(LV2UI_Handle gui) {
00289           static_cast<Derived*>(gui)->presets_cleared();
00290         }
00291         
00292         static void _current_preset_changed(LV2UI_Handle gui, 
00293                                              uint32_t     number) {
00294           static_cast<Derived*>(gui)->current_preset_changed(number);
00295         }
00296         
00297         
00298         LV2UI_Presets_Feature* m_hdesc;
00299         bool m_host_support;
00300         
00301     };
00302 
00303   };
00304 
00305   
00312   template <bool Required = true>
00313   struct WriteMIDI {
00314     
00315     enum {
00316       EVENT_BUFFER_SIZE = 4
00317     };
00318     
00323     template <class Derived> struct I : Extension<Required> {
00324 
00326       I() : m_midi_type(0) {
00327         m_buffer = lv2_event_buffer_new(sizeof(LV2_Event) + EVENT_BUFFER_SIZE, 
00328                                         0);
00329       }
00330       
00332       bool check_ok() {
00333         Derived* d = static_cast<Derived*>(this);
00334         m_midi_type = d->
00335           uri_to_id(LV2_EVENT_URI, "http://lv2plug.in/ns/ext/midi#MidiEvent");
00336         m_event_buffer_format = d->
00337           uri_to_id(LV2_UI_URI, "http://lv2plug.in/ns/extensions/ui#Events");
00338         return !Required || (m_midi_type && m_event_buffer_format);
00339       }
00340       
00341     protected:
00342       
00353       bool write_midi(uint32_t port, uint32_t size, const uint8_t* data) {
00354         if (m_midi_type == 0)
00355           return false;
00356         LV2_Event_Buffer* buffer;
00357         if (size <= 4)
00358           buffer = m_buffer;
00359         else
00360           buffer = lv2_event_buffer_new(sizeof(LV2_Event) + size, 0);
00361         lv2_event_buffer_reset(m_buffer, 0, m_buffer->data);
00362         LV2_Event_Iterator iter;
00363         lv2_event_begin(&iter, m_buffer);
00364         lv2_event_write(&iter, 0, 0, m_midi_type, size, data);
00365         static_cast<Derived*>(this)->
00366           write(port, m_buffer->header_size + m_buffer->capacity, 
00367                 m_event_buffer_format, m_buffer);
00368         if (size > 4)
00369           std::free(buffer);
00370         return true;
00371       }
00372       
00373       uint32_t m_midi_type;
00374       uint32_t m_event_buffer_format;
00375       LV2_Event_Buffer* m_buffer;
00376       
00377     };
00378     
00379   };  
00380   
00381   
00391   template <bool Required = true>
00392   struct WriteOSC {
00393     
00398     template <class Derived> struct I : Extension<Required> {
00399       
00400       I() : m_osc_type(0) {
00401         m_buffer = lv2_event_buffer_new(sizeof(LV2_Event) + 256, 0);
00402       }
00403       
00404       bool check_ok() {
00405         Derived* d = static_cast<Derived*>(this);
00406         m_osc_type = d->
00407           uri_to_id(LV2_EVENT_URI, "http://lv2plug.in/ns/ext/osc#OscEvent");
00408         m_event_buffer_format = d->
00409           uri_to_id(LV2_UI_URI, "http://lv2plug.in/ns/extensions/ui#Events");
00410         return !Required || (m_osc_type && m_event_buffer_format);
00411       }
00412       
00413     protected:
00414       
00415       bool write_osc(uint32_t port, const char* path, const char* types, ...) {
00416         if (m_osc_type == 0)
00417           return false;
00418         // XXX handle all sizes here - this is dangerous
00419         lv2_event_buffer_reset(m_buffer, 0, m_buffer->data);
00420         LV2_Event_Iterator iter;
00421         lv2_event_begin(&iter, m_buffer);
00422         va_list ap;
00423         va_start(ap, types);
00424         uint32_t size = lv2_osc_event_vsize(path, types, ap);
00425         va_end(ap);
00426         if (!size)
00427           return false;
00428         va_start(ap, types);
00429         bool success = lv2_osc_buffer_vappend(&iter, 0, 0, m_osc_type, 
00430                                               path, types, size, ap);
00431         va_end(ap);
00432         if (success) {
00433           static_cast<Derived*>(this)->
00434             write(port, m_buffer->header_size + m_buffer->capacity, 
00435                   m_event_buffer_format, m_buffer);
00436           return true;
00437         }
00438         return false;
00439       }
00440       
00441       uint32_t m_osc_type;
00442       uint32_t m_event_buffer_format;
00443       LV2_Event_Buffer* m_buffer;
00444       
00445     };
00446     
00447   };  
00448   
00449   
00466   template<class Derived, class Ext1 = End, class Ext2 = End, class Ext3 = End,
00467            class Ext4 = End, class Ext5 = End, class Ext6 = End,
00468            class Ext7 = End, class Ext8 = End, class Ext9 = End>
00469   class GUI : public Gtk::HBox, public MixinTree<Derived, 
00470                                                  Ext1, Ext2, Ext3, Ext4, 
00471                                                  Ext5, Ext6, Ext7, Ext8, Ext9> {
00472   public:
00473     
00477     inline GUI() {
00478       m_ctrl = s_ctrl;
00479       m_wfunc = s_wfunc;
00480       m_features = s_features;
00481       m_bundle_path = s_bundle_path;
00482       s_ctrl = 0;
00483       s_wfunc = 0;
00484       s_features = 0;
00485       s_bundle_path = 0;
00486       if (m_features) {
00487         FeatureHandlerMap hmap;
00488         Derived::map_feature_handlers(hmap);
00489         for (const Feature* const* iter = m_features; *iter != 0; ++iter) {
00490           FeatureHandlerMap::iterator miter;
00491           miter = hmap.find((*iter)->URI);
00492           if (miter != hmap.end())
00493             miter->second(static_cast<Derived*>(this), (*iter)->data);
00494         }
00495       }
00496     }
00497     
00500     inline void port_event(uint32_t port, uint32_t buffer_size, 
00501                            uint32_t format, void const* buffer) { }
00502     
00504     static int register_class(char const* uri) {
00505       LV2UI_Descriptor* desc = new LV2UI_Descriptor;
00506       std::memset(desc, 0, sizeof(LV2UI_Descriptor));
00507       desc->URI = strdup(uri);
00508       desc->instantiate = &Derived::create_ui_instance;
00509       desc->cleanup = &Derived::delete_ui_instance;
00510       desc->port_event = &Derived::_port_event;
00511       desc->extension_data = &Derived::extension_data;
00512       get_lv2g2g_descriptors().push_back(desc);
00513       return get_lv2g2g_descriptors().size() - 1;
00514     }
00515     
00516   protected:
00517     
00522     inline void write(uint32_t port, uint32_t buffer_size, 
00523                       uint32_t format, void const* buffer) {
00524       (*m_wfunc)(m_ctrl, port, buffer_size, format, buffer);
00525     }
00526     
00528     inline void write_control(uint32_t port, float value) {
00529       write(port, sizeof(float), 0, &value);
00530     }
00531     
00534     inline LV2::Feature const* const* features() {
00535       return m_features;
00536     }
00537     
00539     inline char const* bundle_path() const {
00540       return m_bundle_path;
00541     }
00542     
00543   public:
00547     inline void* controller() {
00548       return m_ctrl;
00549     }
00550     
00551     
00552   private:
00553     
00554     // This is quite ugly but needed to allow these mixins to call 
00555     // protected functions in the GUI class, which we want.
00556     friend class WriteMIDI<true>::I<Derived>;
00557     friend class WriteMIDI<false>::I<Derived>;
00558     friend class WriteOSC<true>::I<Derived>;
00559     friend class WriteOSC<false>::I<Derived>;
00560     
00565     static LV2UI_Handle create_ui_instance(struct _LV2UI_Descriptor const* 
00566                                            descriptor,
00567                                            char const* plugin_uri,
00568                                            char const* bundle_path,
00569                                            LV2UI_Write_Function write_func,
00570                                            LV2UI_Controller ctrl,
00571                                            LV2UI_Widget* widget,
00572                                            Feature const* const* features) {
00573       
00574       // copy some data to static variables so the subclasses don't have to
00575       // bother with it - this is threadsafe since hosts are not allowed
00576       // to instantiate the same plugin concurrently
00577       s_ctrl = ctrl;
00578       s_wfunc = write_func;
00579       s_features = features;
00580       s_bundle_path = bundle_path;
00581       
00582       // this is needed to initialise gtkmm stuff in case we're running in
00583       // a Gtk+ or PyGtk host or some other language
00584       Gtk::Main::init_gtkmm_internals();
00585       
00586       // create the GUI object
00587       Derived* t = new Derived(plugin_uri);
00588       *widget = static_cast<Gtk::Widget*>(t)->gobj();
00589       
00590       // check that everything is OK
00591       if (t->check_ok())
00592         return reinterpret_cast<LV2UI_Handle>(t);
00593       delete t;
00594       return 0;
00595     }
00596     
00597 
00602     static void delete_ui_instance(LV2UI_Handle instance) {
00603       delete static_cast<Derived*>(instance);
00604     }
00605     
00606     
00610     static void _port_event(LV2UI_Handle instance, uint32_t port, 
00611                             uint32_t buffer_size, uint32_t format, 
00612                             void const* buffer) {
00613       static_cast<Derived*>(instance)->port_event(port, buffer_size, 
00614                                                   format, buffer);
00615     }
00616     
00617 
00618     void* m_ctrl;
00619     LV2UI_Write_Function m_wfunc;
00620     LV2::Feature const* const* m_features;
00621     char const* m_bundle_path;
00622     
00623     static void* s_ctrl;
00624     static LV2UI_Write_Function s_wfunc;
00625     static LV2::Feature const* const* s_features;
00626     static char const* s_bundle_path;
00627     
00628   };
00629 
00630   
00631   /* Yes, static variables are messy. */
00632   template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
00633            class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
00634   void* GUI<Derived, Ext1, Ext2, Ext3, Ext4, 
00635             Ext5, Ext6, Ext7, Ext8, Ext9>::s_ctrl = 0; 
00636   
00637   template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
00638            class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
00639   LV2UI_Write_Function GUI<Derived, Ext1, Ext2, Ext3, Ext4, 
00640                            Ext5, Ext6, Ext7, Ext8, Ext9>::s_wfunc = 0;
00641   
00642   template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
00643            class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
00644   LV2::Feature const* const* GUI<Derived, Ext1, Ext2, Ext3, Ext4, 
00645                                  Ext5, Ext6, Ext7, Ext8, Ext9>::s_features = 0;
00646   
00647   template<class Derived, class Ext1, class Ext2, class Ext3, class Ext4,
00648            class Ext5, class Ext6, class Ext7, class Ext8, class Ext9>
00649   char const* GUI<Derived, Ext1, Ext2, Ext3, Ext4, 
00650                   Ext5, Ext6, Ext7, Ext8, Ext9>::s_bundle_path = 0;
00651   
00652 
00653 }
00654 
00655 
00656 #endif

Generated on Sun Feb 27 2011 13:41:49 by  doxygen 1.7.1