[beast: 1/9] BSE: move ItemSeq, PropertyCandidates, get_property_candidates() into bseapi.idl



commit 87e06c3cab5f788adfd0ceb2b5062c94108b4cce
Author: Tim Janik <timj gnu org>
Date:   Wed Sep 27 01:45:07 2017 +0200

    BSE: move ItemSeq, PropertyCandidates, get_property_candidates() into bseapi.idl
    
    Signed-off-by: Tim Janik <timj gnu org>

 bse/bseapi.idl          |   23 ++++-
 bse/bsebasics.idl       |    7 --
 bse/bsebus.cc           |  234 ++++++++++++++++++++++++++++++-----------------
 bse/bsebus.hh           |    7 +-
 bse/bsecxxbase.cc       |    2 +-
 bse/bsecxxbase.hh       |    4 +-
 bse/bsecxxplugin.hh     |   11 +--
 bse/bseitem.cc          |   59 +++++-------
 bse/bseitem.hh          |   22 +----
 bse/bseitem.proc        |   33 -------
 bse/bsemidisynth.cc     |   15 ++--
 bse/bsesong.cc          |   10 +-
 bse/bsesoundfontosc.cc  |   14 +--
 bse/bsesoundfontrepo.cc |   11 +-
 bse/bsesoundfontrepo.hh |    2 +-
 bse/bsesubsynth.cc      |   10 +-
 bse/bsetrack.cc         |   38 +++++---
 bse/bseutils.cc         |   33 +++----
 bse/bseutils.hh         |    8 +-
 bse/bsewaveosc.cc       |   10 +-
 20 files changed, 272 insertions(+), 281 deletions(-)
---
diff --git a/bse/bseapi.idl b/bse/bseapi.idl
index 3fdea69..d2a1e73 100644
--- a/bse/bseapi.idl
+++ b/bse/bseapi.idl
@@ -626,6 +626,7 @@ record PartLink;
 sequence PartLinkSeq;
 record TrackPart;
 sequence TrackPartSeq;
+interface Item;
 interface Project;
 
 /// Fundamental base type for all BSE objects.
@@ -636,6 +637,21 @@ interface Object {
   signal void changed    (String what); ///< Notification for object state or property changes.
 };
 
+/// A list of Item or derived objects.
+sequence ItemSeq {
+  Item items;
+};
+
+/// A list of items suitable to set as a specific property value.
+record PropertyCandidates {
+  Info      blurb      = ("A structure describing tentative property values.");
+  String    label;
+  String    tooltip;
+  ItemSeq   items;
+  // List of types which may logically partition the list of items by type discrimination
+  StringSeq partitions;
+};
+
 /// Base interface type for objects that can be added to a container.
 interface Item : Object {
   Icon    icon = Record ("Icon", "State dependent icon representation of this item", "rw:G");
@@ -659,15 +675,10 @@ interface Item : Object {
   String  get_name_or_type  (); ///< Retrieve an item's name or type if it has no name.
   bool    internal          (); ///< Check whether an item is internal, i.e. owned by another non-internal 
item.
   bool    editable_property (String property); ///< Test whether a property is editable according to object 
state and property options.
-  // PropertyCandidates get_property_candidates (String property_name); ///< Retrieve tentative values for 
an item or item sequence property.
+  PropertyCandidates get_property_candidates (String property_name); ///< Retrieve tentative values for an 
item or item sequence property.
   // int32 seqid = Range ("Sequential ID", "", ":readwrite", 0, MAXINT31, 1);
 };
 
-/// A list of part note events.
-sequence ItemSeq {
-  Item items;
-};
-
 /// Part specific note event representation.
 record PartNote
 {
diff --git a/bse/bsebasics.idl b/bse/bsebasics.idl
index 52fa70b..11ee14f 100644
--- a/bse/bsebasics.idl
+++ b/bse/bsebasics.idl
@@ -79,13 +79,6 @@ sequence It3mSeq {
   Info   blurb = ("A list of BSE items or derived types.");
   Item   items;
 };
-record PropertyCandidates {
-  Info    blurb      = ("A structure describing tentative property values.");
-  SfiString  label;
-  SfiString  tooltip;
-  It3mSeq items;
-  TypeSeq partitions = SfiSeq ("Type Partitions", "List of types which may logically partition the list of 
items by type discrimination", STANDARD);
-};
 record NoteSequence
 {
   Int     offset = Note ("Note Offset", "Center/base note", KAMMER_NOTE, ":readwrite");
diff --git a/bse/bsebus.cc b/bse/bsebus.cc
index 540f780..0049080 100644
--- a/bse/bsebus.cc
+++ b/bse/bsebus.cc
@@ -87,20 +87,18 @@ get_master (BseBus *self)
 }
 
 static void
-bus_list_input_candidates (BseBus     *self,
-                           BseIt3mSeq *iseq)
+bus_list_input_candidates (BseBus *self, Bse::ItemSeq &iseq)
 {
   BseItem *item = BSE_ITEM (self);
   bse_item_gather_items_typed (item, iseq, BSE_TYPE_BUS, BSE_TYPE_SONG, FALSE);
   bse_item_gather_items_typed (item, iseq, BSE_TYPE_TRACK, BSE_TYPE_SONG, FALSE);
   BseBus *master = get_master (self);
   if (master)
-    bse_it3m_seq_remove (iseq, BSE_ITEM (master));
+    vector_erase_element (iseq, master->as<Bse::ItemIfaceP>());
 }
 
 void
-bse_bus_or_track_list_output_candidates (BseItem    *trackbus,
-                                         BseIt3mSeq *iseq)
+bse_bus_or_track_list_output_candidates (BseItem *trackbus, Bse::ItemSeq &iseq)
 {
   if (BSE_IS_BUS (trackbus) || BSE_IS_TRACK (trackbus))
     bse_item_gather_items_typed (trackbus, iseq, BSE_TYPE_BUS, BSE_TYPE_SONG, FALSE);
@@ -109,7 +107,7 @@ bse_bus_or_track_list_output_candidates (BseItem    *trackbus,
 static void
 bse_bus_get_candidates (BseItem               *item,
                         guint                  param_id,
-                        BsePropertyCandidates *pc,
+                        Bse::PropertyCandidates &pc,
                         GParamSpec            *pspec)
 {
   BseBus *self = BSE_BUS (item);
@@ -117,23 +115,31 @@ bse_bus_get_candidates (BseItem               *item,
     {
       SfiRing *ring;
     case PROP_INPUTS:
-      bse_property_candidate_relabel (pc, _("Available Inputs"), _("List of available synthesis signals to 
be used as bus input"));
-      bus_list_input_candidates (self, pc->items);
+      pc.label = _("Available Inputs");
+      pc.tooltip = _("List of available synthesis signals to be used as bus input");
+      bus_list_input_candidates (self, pc.items);
       /* remove existing inputs from candidates */
       ring = bse_bus_list_inputs (self);
       while (ring)
-        bse_it3m_seq_remove (pc->items, (BseItem*) sfi_ring_pop_head (&ring));
+        {
+          BseItem *item = (BseItem*) sfi_ring_pop_head (&ring);
+          vector_erase_element (pc.items, item->as<Bse::ItemIfaceP>());
+        }
       /* SYNC: type partitions */
-      bse_type_seq_append (pc->partitions, "BseTrack");
-      bse_type_seq_append (pc->partitions, "BseBus");
+      pc.partitions.push_back ("BseTrack");
+      pc.partitions.push_back ("BseBus");
       break;
     case PROP_OUTPUTS:
-      bse_property_candidate_relabel (pc, _("Available Outputs"), _("List of available mixer busses to be 
used as bus output"));
-      bse_bus_or_track_list_output_candidates (BSE_ITEM (self), pc->items);
+      pc.label = _("Available Outputs");
+      pc.tooltip = _("List of available mixer busses to be used as bus output");
+      bse_bus_or_track_list_output_candidates (BSE_ITEM (self), pc.items);
       /* remove existing outputs */
       ring = bse_bus_list_outputs (self);
       while (ring)
-        bse_it3m_seq_remove (pc->items, (BseItem*) sfi_ring_pop_head (&ring));
+        {
+          BseItem *item = (BseItem*) sfi_ring_pop_head (&ring);
+          vector_erase_element (pc.items, item->as<Bse::ItemIfaceP>());
+        }
       break;
     case PROP_SNET:
       break;
@@ -236,44 +242,125 @@ bus_volume_changed (BseBus *self)
 }
 
 void
-bse_bus_or_track_set_outputs (BseItem        *trackbus,
-                              BseIt3mSeq     *outputs_iseq)
+bse_bus_set_inputs (BseBus *self, const Bse::ItemSeq &inputs_iseq)
+{
+  // convert and sort existing bus outputs
+  std::vector<BseItem*> bus_inputs;
+  for (SfiRing *ring = self->inputs; ring; ring = sfi_ring_walk (ring, self->inputs))
+    bus_inputs.push_back ((BseItem*) ring->data);
+  std::stable_sort (bus_inputs.begin(), bus_inputs.end());                      // self->inputs
+  // sort the new set of input items
+  std::vector<BseItem*> inputs;
+  for (Bse::ItemIfaceP itemp : inputs_iseq)
+    inputs.push_back (itemp->as<BseItem*>());
+  std::stable_sort (inputs.begin(), inputs.end());                              // inputs == inputs_iseq
+  // fetch all input candidates
+  Bse::ItemSeq iseq;
+  bus_list_input_candidates (self, iseq);
+  std::vector<BseItem*> candidates;
+  for (Bse::ItemIfaceP itemp : iseq)
+    candidates.push_back (itemp->as<BseItem*>());
+  std::stable_sort (candidates.begin(), candidates.end());
+  // constrain the new output list
+  std::vector<BseItem*> tmp;
+  std::set_intersection (inputs.begin(), inputs.end(), candidates.begin(), candidates.end(), 
std::back_inserter (tmp));
+  inputs.swap (tmp);
+  tmp.clear();
+  // disconnect stale inputs
+  std::set_difference (bus_inputs.begin(), bus_inputs.end(), inputs.begin(), inputs.end(), 
std::back_inserter (tmp));
+  while (!tmp.empty())
+    {
+      BseItem *item = tmp.back();
+      tmp.pop_back();
+      bse_bus_disconnect (self, item);                                          // modifies self->inputs
+    }
+  // add new inputs
+  std::set_difference (inputs.begin(), inputs.end(), bus_inputs.begin(), bus_inputs.end(), 
std::back_inserter (tmp));
+  while (!tmp.empty())
+    {
+      BseItem *item = tmp.back();
+      tmp.pop_back();
+      bse_bus_connect_unchecked (self, item);                                   // modifies self->inputs
+    }
+  // restore self->inputs order to user provided order, given in inputs_iseq
+  bus_inputs.clear();
+  for (SfiRing *ring = self->inputs; ring; ring = sfi_ring_walk (ring, self->inputs))
+    bus_inputs.push_back ((BseItem*) ring->data);                               // self->inputs
+  inputs.clear();
+  for (Bse::ItemIfaceP itemp : inputs_iseq)
+    inputs.push_back (itemp->as<BseItem*>());
+  Bse::copy_reordered (bus_inputs.begin(), bus_inputs.end(), inputs.begin(), inputs.end(), 
std::back_inserter (tmp));
+  assert_return (bus_inputs.size() == tmp.size());
+  SfiRing *newring = NULL;
+  for (BseItem *item : tmp)
+    newring = sfi_ring_append (newring, item);
+  sfi_ring_free (self->inputs);
+  self->inputs = newring;
+}
+
+void
+bse_bus_or_track_set_outputs (BseItem *trackbus, const Bse::ItemSeq &outputs_iseq)
 {
   SfiRing **pbus_outputs;
-  /* handle object types */
+  // pick bus output depending on object type
   if (BSE_IS_BUS (trackbus))
     pbus_outputs = &BSE_BUS (trackbus)->bus_outputs;
   else if (BSE_IS_TRACK (trackbus))
     pbus_outputs = &BSE_TRACK (trackbus)->bus_outputs;
   else
     return;
-  /* save user provided order */
-  SfiRing *saved_outputs = bse_it3m_seq_to_ring (outputs_iseq);
-  /* provide sorted rings: bus_outputs, outputs */
-  SfiRing *outputs = sfi_ring_sort (sfi_ring_copy (saved_outputs), sfi_pointer_cmp, NULL);
-  *pbus_outputs = sfi_ring_sort (*pbus_outputs, sfi_pointer_cmp, NULL);
-  /* get all output candidates */
-  BseIt3mSeq *iseq = bse_it3m_seq_new();
+  // convert and sort existing bus outputs
+  std::vector<BseItem*> bus_outputs;
+  for (SfiRing *ring = *pbus_outputs; ring; ring = sfi_ring_walk (ring, *pbus_outputs))
+    bus_outputs.push_back ((BseItem*) ring->data);
+  std::stable_sort (bus_outputs.begin(), bus_outputs.end());
+  // sort the new set of output items
+  std::vector<BseItem*> outputs;
+  for (Bse::ItemIfaceP itemp : outputs_iseq)
+    outputs.push_back (itemp->as<BseItem*>());
+  std::stable_sort (outputs.begin(), outputs.end());
+  // fetch all output candidates
+  Bse::ItemSeq iseq;
   bse_bus_or_track_list_output_candidates (trackbus, iseq);
-  SfiRing *candidates = sfi_ring_sort (bse_it3m_seq_to_ring (iseq), sfi_pointer_cmp, NULL);
-  bse_it3m_seq_free (iseq);
-  /* constrain the new output list */
-  SfiRing *ring = sfi_ring_intersection (outputs, candidates, sfi_pointer_cmp, NULL);
-  sfi_ring_free (candidates);
-  sfi_ring_free (outputs);
-  outputs = ring;
-  /* remove stale outputs */
-  ring = sfi_ring_difference (*pbus_outputs, outputs, sfi_pointer_cmp, NULL);
-  while (ring)
-    bse_bus_disconnect ((BseBus*) sfi_ring_pop_head (&ring), trackbus);
-  /* add new outputs */
-  ring = sfi_ring_difference (outputs, *pbus_outputs, sfi_pointer_cmp, NULL);
-  while (ring)
-    bse_bus_connect_unchecked ((BseBus*) sfi_ring_pop_head (&ring), trackbus);
-  sfi_ring_free (outputs);
-  /* restore user provided order */
-  *pbus_outputs = sfi_ring_reorder (*pbus_outputs, saved_outputs);
-  sfi_ring_free (saved_outputs);
+  std::vector<BseItem*> candidates;
+  for (Bse::ItemIfaceP itemp : iseq)
+    candidates.push_back (itemp->as<BseItem*>());
+  std::stable_sort (candidates.begin(), candidates.end());
+  // constrain the new output list
+  std::vector<BseItem*> tmp;
+  std::set_intersection (outputs.begin(), outputs.end(), candidates.begin(), candidates.end(), 
std::back_inserter (tmp));
+  outputs.swap (tmp);
+  tmp.clear();
+  // disconnect stale outputs
+  std::set_difference (bus_outputs.begin(), bus_outputs.end(), outputs.begin(), outputs.end(), 
std::back_inserter (tmp));
+  while (!tmp.empty())
+    {
+      BseItem *item = tmp.back();
+      tmp.pop_back();
+      bse_bus_disconnect (BSE_BUS (item), trackbus);            // modifies trackbus->bus_outputs
+    }
+  // add new outputs
+  std::set_difference (outputs.begin(), outputs.end(), bus_outputs.begin(), bus_outputs.end(), 
std::back_inserter (tmp));
+  while (!tmp.empty())
+    {
+      BseItem *item = tmp.back();
+      tmp.pop_back();
+      bse_bus_connect_unchecked (BSE_BUS (item), trackbus);     // modifies trackbus->bus_outputs
+    }
+  // restore pbus_outputs order to user provided order, given in outputs_iseq
+  bus_outputs.clear();
+  for (SfiRing *ring = *pbus_outputs; ring; ring = sfi_ring_walk (ring, *pbus_outputs))
+    bus_outputs.push_back ((BseItem*) ring->data);
+  outputs.clear();
+  for (Bse::ItemIfaceP itemp : outputs_iseq)
+    outputs.push_back (itemp->as<BseItem*>());
+  Bse::copy_reordered (bus_outputs.begin(), bus_outputs.end(), outputs.begin(), outputs.end(), 
std::back_inserter (tmp));
+  assert_return (bus_outputs.size() == tmp.size());
+  SfiRing *newring = NULL;
+  for (BseItem *item : tmp)
+    newring = sfi_ring_append (newring, item);
+  sfi_ring_free (*pbus_outputs);
+  *pbus_outputs = newring;
 }
 
 static void
@@ -285,41 +372,21 @@ bse_bus_set_property (GObject      *object,
   BseBus *self = BSE_BUS (object);
   switch (param_id)
     {
-      SfiRing *inputs, *candidates, *ring, *saved_inputs;
-      BseIt3mSeq *iseq;
       BseItem *parent;
       gboolean vbool;
     case PROP_INPUTS:
-      /* save user provided order */
-      saved_inputs = bse_it3m_seq_to_ring ((BseIt3mSeq*) g_value_get_boxed (value));
-      /* provide sorted rings: self->inputs, inputs */
-      inputs = sfi_ring_sort (sfi_ring_copy (saved_inputs), sfi_pointer_cmp, NULL);
-      self->inputs = sfi_ring_sort (self->inputs, sfi_pointer_cmp, NULL);
-      /* get all input candidates */
-      iseq = bse_it3m_seq_new();
-      bus_list_input_candidates (self, iseq);
-      candidates = sfi_ring_sort (bse_it3m_seq_to_ring (iseq), sfi_pointer_cmp, NULL);
-      bse_it3m_seq_free (iseq);
-      /* constrain the new input list */
-      ring = sfi_ring_intersection (inputs, candidates, sfi_pointer_cmp, NULL);
-      sfi_ring_free (candidates);
-      sfi_ring_free (inputs);
-      inputs = ring;
-      /* remove stale inputs */
-      ring = sfi_ring_difference (self->inputs, inputs, sfi_pointer_cmp, NULL);
-      while (ring)
-        bse_bus_disconnect (self, (BseItem*) sfi_ring_pop_head (&ring));
-      /* add new inputs */
-      ring = sfi_ring_difference (inputs, self->inputs, sfi_pointer_cmp, NULL);
-      while (ring)
-        bse_bus_connect_unchecked (self, (BseItem*) sfi_ring_pop_head (&ring));
-      sfi_ring_free (inputs);
-      /* restore user provided order */
-      self->inputs = sfi_ring_reorder (self->inputs, saved_inputs);
-      sfi_ring_free (saved_inputs);
+      {
+        BseIt3mSeq *i3s = (BseIt3mSeq*) g_value_get_boxed (value);
+        Bse::ItemSeq items = bse_item_seq_from_it3m_seq (i3s);
+        bse_bus_set_inputs (self, items);
+      }
       break;
     case PROP_OUTPUTS:
-      bse_bus_or_track_set_outputs (BSE_ITEM (self), (BseIt3mSeq*) g_value_get_boxed (value));
+      {
+        BseIt3mSeq *i3s = (BseIt3mSeq*) g_value_get_boxed (value);
+        Bse::ItemSeq items = bse_item_seq_from_it3m_seq (i3s);
+        bse_bus_or_track_set_outputs (BSE_ITEM (self), items);
+      }
       break;
     case PROP_SNET:
       g_object_set_property (G_OBJECT (self), "BseSubSynth::snet", value);
@@ -648,23 +715,20 @@ bus_uncross_input (BseItem *owner,
 }
 
 Bse::Error
-bse_bus_connect (BseBus  *self,
-                 BseItem *trackbus)
+bse_bus_connect (BseBus *self, BseItem *trackbus)
 {
-  /* get all input candidates */
-  BseIt3mSeq *iseq = bse_it3m_seq_new();
+  // get all input candidates
+  Bse::ItemSeq iseq;
   bus_list_input_candidates (self, iseq);
-  /* find trackbus */
-  gboolean found_candidate = FALSE;
-  guint i;
-  for (i = 0; i < iseq->n_items; i++)
-    if (iseq->items[i] == trackbus)
+  // find trackbus
+  bool found_candidate = false;
+  for (size_t i = 0; i < iseq.size(); i++)
+    if (iseq[i]->as<BseItem*>() == trackbus)
       {
-        found_candidate = TRUE;
+        found_candidate = true;
         break;
       }
-  bse_it3m_seq_free (iseq);
-  /* add trackbus if valid */
+  // add trackbus if valid
   if (found_candidate)
     return bse_bus_connect_unchecked (self, trackbus);
   else
diff --git a/bse/bsebus.hh b/bse/bsebus.hh
index c0428f6..76d3109 100644
--- a/bse/bsebus.hh
+++ b/bse/bsebus.hh
@@ -54,11 +54,10 @@ Bse::Error    bse_bus_replace_effect          (BseBus         *self,
                                                  const gchar    *etype);
 void            bse_bus_change_solo             (BseBus         *self,
                                                  gboolean        solo_muted);
+void            bse_bus_set_inputs              (BseBus *self, const Bse::ItemSeq &iseq);
 #define         bse_bus_create_stack(b)         bse_bus_get_stack (b,0,0,0)
-void    bse_bus_or_track_list_output_candidates (BseItem        *trackbus,
-                                                 BseIt3mSeq     *iseq);
-void    bse_bus_or_track_set_outputs            (BseItem        *trackbus,
-                                                 BseIt3mSeq     *iseq);
+void    bse_bus_or_track_list_output_candidates (BseItem *trackbus, Bse::ItemSeq &iseq);
+void    bse_bus_or_track_set_outputs            (BseItem *trackbus, const Bse::ItemSeq &iseq);
 
 /* --- channels --- */
 enum
diff --git a/bse/bsecxxbase.cc b/bse/bsecxxbase.cc
index 36a9835..3dd8288 100644
--- a/bse/bsecxxbase.cc
+++ b/bse/bsecxxbase.cc
@@ -260,7 +260,7 @@ void
 CxxBaseClass::set_accessors (void       (*get_property)      (GObject*,   guint,       GValue*,          
GParamSpec*),
                              void       (*set_property)      (GObject*,   guint, const GValue*,          
GParamSpec*),
                              gboolean   (*editable_property) (BseObject*, guint,                         
GParamSpec*),
-                             void       (*get_candidates)    (BseItem*,   guint, BsePropertyCandidates*, 
GParamSpec*),
+                             void       (*get_candidates)    (BseItem*,   guint, Bse::PropertyCandidates&, 
GParamSpec*),
                              void       (*property_updated)  (BseSource*, guint, guint64, double,        
GParamSpec*))
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (this);
diff --git a/bse/bsecxxbase.hh b/bse/bsecxxbase.hh
index 044c63d..4a576ea 100644
--- a/bse/bsecxxbase.hh
+++ b/bse/bsecxxbase.hh
@@ -21,7 +21,7 @@ public:
   void  set_accessors (void       (*get_property)      (GObject*,   guint,       GValue*,          
GParamSpec*),
                        void       (*set_property)      (GObject*,   guint, const GValue*,          
GParamSpec*) = NULL,
                        gboolean   (*editable_property) (BseObject*, guint,                         
GParamSpec*) = NULL,
-                       void       (*get_candidates)    (BseItem*,   guint, BsePropertyCandidates*, 
GParamSpec*) = NULL,
+                       void       (*get_candidates)    (BseItem*,   guint, Bse::PropertyCandidates&, 
GParamSpec*) = NULL,
                        void       (*property_updated)  (BseSource*, guint, guint64, double,        
GParamSpec*) = NULL);
   guint add_signal    (const gchar *signal_name,
                        GSignalFlags flags,
@@ -225,7 +225,7 @@ cxx_editable_property_trampoline (BseObject    *o,
 template<class ObjectType, typename PropertyID> static void
 cxx_get_candidates_trampoline (BseItem               *item,
                                guint                  prop_id,
-                               BsePropertyCandidates *pc,
+                               Bse::PropertyCandidates &pc,
                                GParamSpec            *pspec);   /* defined in bsecxxplugin.hh */
 
 template<class ObjectType, typename PropertyID> static void
diff --git a/bse/bsecxxplugin.hh b/bse/bsecxxplugin.hh
index a32a948..420c670 100644
--- a/bse/bsecxxplugin.hh
+++ b/bse/bsecxxplugin.hh
@@ -340,20 +340,15 @@ namespace Bse {
 template<class ObjectType, typename PropertyID> static void
 cxx_get_candidates_trampoline (BseItem               *item,
                                guint                  prop_id,
-                               BsePropertyCandidates *pc,
+                               Bse::PropertyCandidates &pc,
                                GParamSpec            *pspec)
 {
   CxxBase *cbase = cast (item);
   ObjectType *instance = static_cast<ObjectType*> (cbase);
   if (0)        // check ObjectType::get_candidates() member and prototype
-    (void) static_cast<void (ObjectType::*) (PropertyID, ::Bse::PropertyCandidatesHandle&, GParamSpec*)> 
(&ObjectType::get_candidates);
-  ::Bse::PropertyCandidatesHandle pch (::Sfi::INIT_NULL);
-  ::Bse::PropertyCandidates *cxxpc = (::Bse::PropertyCandidates*) pc;
-  if (cxxpc)
-    pch.take (cxxpc);   /* take as pointer, not via CopyConstructor */
+    (void) static_cast<void (ObjectType::*) (PropertyID, ::Bse::PropertyCandidates&, GParamSpec*)> 
(&ObjectType::get_candidates);
+  ::Bse::PropertyCandidates pch;
   instance->get_candidates (static_cast<PropertyID> (prop_id), pch, pspec);
-  if (cxxpc)
-    pch.steal();        /* steal to avoid destruction */
 }
 
 } // Bse
diff --git a/bse/bseitem.cc b/bse/bseitem.cc
index d6a1db0..4d19e35 100644
--- a/bse/bseitem.cc
+++ b/bse/bseitem.cc
@@ -286,7 +286,7 @@ bse_item_compat_setup (BseItem         *self,
 typedef struct {
   BseItem              *item;
   void                 *data;
-  BseIt3mSeq           *iseq;
+  Bse::ItemSeq          iseq;
   GType                 base_type;
   BseItemCheckContainer ccheck;
   BseItemCheckProxy     pcheck;
@@ -301,7 +301,7 @@ gather_child (BseItem *child,
   if (child != gdata->item && !BSE_ITEM_INTERNAL (child) &&
       g_type_is_a (G_OBJECT_TYPE (child), gdata->base_type) &&
       (!gdata->pcheck || gdata->pcheck (child, gdata->item, gdata->data)))
-    bse_it3m_seq_append (gdata->iseq, child);
+    gdata->iseq.push_back (child->as<Bse::ItemIfaceP>());
   return TRUE;
 }
 
@@ -312,25 +312,17 @@ gather_child (BseItem *child,
  * @param ccheck       container filter function
  * @param pcheck       proxy filter function
  * @param data         @a data pointer to @a ccheck and @a pcheck
- * @return             returns @a items
  *
  * This function gathers items from an object hierachy, walking upwards,
  * starting out with @a item. For each container passing @a ccheck(), all
  * immediate children are tested for addition with @a pcheck.
  */
-BseIt3mSeq*
-bse_item_gather_items (BseItem              *item,
-                       BseIt3mSeq           *iseq,
-                       GType                 base_type,
-                       BseItemCheckContainer ccheck,
-                       BseItemCheckProxy     pcheck,
-                       void                 *data)
+static void
+bse_item_gather_items (BseItem *item, Bse::ItemSeq &iseq, GType base_type, BseItemCheckContainer ccheck, 
BseItemCheckProxy pcheck, void *data)
 {
   GatherData gdata;
-
-  assert_return (BSE_IS_ITEM (item), NULL);
-  assert_return (iseq != NULL, NULL);
-  assert_return (g_type_is_a (base_type, BSE_TYPE_ITEM), NULL);
+  assert_return (BSE_IS_ITEM (item));
+  assert_return (g_type_is_a (base_type, BSE_TYPE_ITEM));
 
   gdata.item = item;
   gdata.data = data;
@@ -347,7 +339,6 @@ bse_item_gather_items (BseItem              *item,
         bse_container_forall_items (container, gather_child, &gdata);
       item = item->parent;
     }
-  return iseq;
 }
 
 static gboolean
@@ -373,46 +364,32 @@ gather_typed_acheck (BseItem  *proxy,
  * @param proxy_type    base type of the items to gather
  * @param container_type base type of the containers to check for items
  * @param allow_ancestor if FALSE, ancestors of @a item are omitted
- * @return              returns @a items
  *
  * Variant of bse_item_gather_items(), the containers and items
  * are simply filtered by checking derivation from @a container_type
  * and @a proxy_type respectively. Gathered items may not be ancestors
- * of @a item if @a allow_ancestor is FALSE.
+ * of @a item if @a allow_ancestor is @a false.
  */
-BseIt3mSeq*
-bse_item_gather_items_typed (BseItem              *item,
-                             BseIt3mSeq           *iseq,
-                             GType                 proxy_type,
-                             GType                 container_type,
-                             gboolean              allow_ancestor)
+void
+bse_item_gather_items_typed (BseItem *item, Bse::ItemSeq &iseq, GType proxy_type, GType container_type, bool 
allow_ancestor)
 {
   if (allow_ancestor)
-    return bse_item_gather_items (item, iseq, proxy_type, gather_typed_ccheck, NULL, (void*) container_type);
+    bse_item_gather_items (item, iseq, proxy_type, gather_typed_ccheck, NULL, (void*) container_type);
   else
-    return bse_item_gather_items (item, iseq, proxy_type,
-                                  gather_typed_ccheck, gather_typed_acheck, (void*) container_type);
+    bse_item_gather_items (item, iseq, proxy_type, gather_typed_ccheck, gather_typed_acheck, (void*) 
container_type);
 }
 
 gboolean
-bse_item_get_candidates (BseItem                *item,
-                         const char             *property,
-                         BsePropertyCandidates  *pc)
+bse_item_get_candidates (BseItem *item, const Bse::String &property, Bse::PropertyCandidates &pc)
 {
   BseItemClass *klass;
   GParamSpec *pspec;
 
   assert_return (BSE_IS_ITEM (item), FALSE);
-  assert_return (property != NULL, FALSE);
-  assert_return (pc != NULL, FALSE);
 
-  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (item), property);
+  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (item), property.c_str());
   if (!pspec)
     return FALSE;
-  if (!pc->items)
-    pc->items = bse_it3m_seq_new();
-  if (!pc->partitions)
-    pc->partitions = bse_type_seq_new();
   klass = (BseItemClass*) g_type_class_peek (pspec->owner_type);
   if (klass && klass->get_candidates)
     klass->get_candidates (item, pspec->param_id, pc, pspec);
@@ -1535,4 +1512,14 @@ ItemImpl::internal ()
   return BSE_ITEM_INTERNAL (self);
 }
 
+PropertyCandidates
+ItemImpl::get_property_candidates (const String &property_name)
+{
+  BseItem *self = as<BseItem*>();
+  PropertyCandidates pc;
+  if (bse_item_get_candidates (self, property_name, pc))
+    return pc;
+  return PropertyCandidates();
+}
+
 } // Bse
diff --git a/bse/bseitem.hh b/bse/bseitem.hh
index 1e66ca0..41591ab 100644
--- a/bse/bseitem.hh
+++ b/bse/bseitem.hh
@@ -35,10 +35,7 @@ struct BseItem : BseObject {
 };
 
 struct BseItemClass : BseObjectClass {
-  void          (*get_candidates) (BseItem               *item,
-                                   guint                  param_id,
-                                   BsePropertyCandidates *pc,
-                                   GParamSpec            *pspec);
+  void          (*get_candidates) (BseItem *item, uint param_id, Bse::PropertyCandidates &pc, GParamSpec 
*pspec);
   void          (*set_parent)     (BseItem               *item,
                                    BseItem               *parent);
   gboolean      (*needs_storage)  (BseItem               *item,
@@ -62,20 +59,10 @@ typedef gboolean (*BseItemCheckProxy)        (BseItem        *proxy,
 
 
 /* --- prototypes --- */
-BseIt3mSeq*    bse_item_gather_items         (BseItem                *item,
-                                              BseIt3mSeq             *iseq,
-                                              GType                   base_type,
-                                              BseItemCheckContainer   ccheck,
-                                              BseItemCheckProxy       pcheck,
-                                              gpointer                data);
-BseIt3mSeq*    bse_item_gather_items_typed   (BseItem                *item,
-                                              BseIt3mSeq             *iseq,
-                                              GType                   proxy_type,
-                                              GType                   container_type,
-                                              gboolean                allow_ancestor);
+void            bse_item_gather_items_typed   (BseItem *item, Bse::ItemSeq &iseq, GType proxy_type, GType 
container_type, bool allow_ancestor);
 gboolean        bse_item_get_candidates      (BseItem                *item,
-                                              const gchar            *property,
-                                              BsePropertyCandidates  *pc);
+                                              const Bse::String      &property,
+                                              Bse::PropertyCandidates &pc);
 void            bse_item_set_internal        (gpointer         item,
                                               gboolean         internal);
 gboolean        bse_item_needs_storage       (BseItem         *item,
@@ -183,6 +170,7 @@ public:
   virtual String        get_name         () override;
   virtual String        get_name_or_type () override;
   virtual bool          internal         () override;
+  virtual PropertyCandidates get_property_candidates (const String &property_name) override;
   /// Save the value of @a property_name onto the undo stack.
   void               push_property_undo  (const String &property_name);
   /// Push an undo @a function onto the undo stack, the @a self argument to @a function must match @a this.
diff --git a/bse/bseitem.proc b/bse/bseitem.proc
index 788dd3a..873c6a3 100644
--- a/bse/bseitem.proc
+++ b/bse/bseitem.proc
@@ -10,36 +10,3 @@
 
 AUTHORS        = "Tim Janik <timj gtk org>";
 LICENSE = "GNU Lesser General Public License";
-
-
-METHOD (BseItem, get-property-candidates) {
-  HELP = "Retrieve tentative values for an item or item sequence property.";
-  IN   = bse_param_spec_object ("item", NULL, NULL,
-                                BSE_TYPE_ITEM, SFI_PARAM_STANDARD);
-  IN   = sfi_pspec_string ("property_name", NULL, "Item property name",
-                           NULL, SFI_PARAM_STANDARD);
-  OUT  = bse_param_spec_boxed ("candidates", "Candidates", NULL, BSE_TYPE_PROPERTY_CANDIDATES, 
SFI_PARAM_STANDARD);
-} BODY (BseProcedureClass *proc,
-       const GValue      *in_values,
-       GValue            *out_values)
-{
-  /* extract parameter values */
-  BseItem *self = (BseItem*) bse_value_get_object (in_values++);
-  const char   *property = sfi_value_get_string (in_values++);
-
-  /* check parameters */
-  if (!BSE_IS_ITEM (self) || !property)
-    return Bse::Error::PROC_PARAM_INVAL;
-
-  /* set output parameters */
-  BsePropertyCandidates *pc = bse_property_candidates_new();
-  if (!bse_item_get_candidates (self, property, pc))
-    {
-      bse_property_candidates_free (pc);
-      pc = NULL;
-    }
-  bse_value_take_boxed (out_values++, pc);
-
-  return Bse::Error::NONE;
-}
-
diff --git a/bse/bsemidisynth.cc b/bse/bsemidisynth.cc
index d7d6626..0c9f9ad 100644
--- a/bse/bsemidisynth.cc
+++ b/bse/bsemidisynth.cc
@@ -199,21 +199,20 @@ bse_midi_synth_finalize (GObject *object)
 }
 
 static void
-bse_midi_synth_get_candidates (BseItem               *item,
-                               guint                  param_id,
-                               BsePropertyCandidates *pc,
-                               GParamSpec            *pspec)
+bse_midi_synth_get_candidates (BseItem *item, uint param_id, Bse::PropertyCandidates &pc, GParamSpec *pspec)
 {
   BseMidiSynth *self = BSE_MIDI_SYNTH (item);
   switch (param_id)
     {
     case PROP_SNET:
-      bse_property_candidate_relabel (pc, _("Available Synthesizers"), _("List of available synthesis 
networks to choose a MIDI instrument from"));
-      bse_item_gather_items_typed (item, pc->items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
+      pc.label = _("Available Synthesizers");
+      pc.tooltip = _("List of available synthesis networks to choose a MIDI instrument from");
+      bse_item_gather_items_typed (item, pc.items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
       break;
     case PROP_PNET:
-      bse_property_candidate_relabel (pc, _("Available Postprocessors"), _("List of available synthesis 
networks to choose a postprocessor from"));
-      bse_item_gather_items_typed (item, pc->items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
+      pc.label = _("Available Postprocessors");
+      pc.tooltip = _("List of available synthesis networks to choose a postprocessor from");
+      bse_item_gather_items_typed (item, pc.items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
diff --git a/bse/bsesong.cc b/bse/bsesong.cc
index a0bf2fc..cb91ade 100644
--- a/bse/bsesong.cc
+++ b/bse/bsesong.cc
@@ -111,17 +111,15 @@ bse_song_finalize (GObject *object)
 }
 
 static void
-bse_song_get_candidates (BseItem               *item,
-                         guint                  param_id,
-                         BsePropertyCandidates *pc,
-                         GParamSpec            *pspec)
+bse_song_get_candidates (BseItem *item, uint param_id, Bse::PropertyCandidates &pc, GParamSpec *pspec)
 {
   BseSong *self = BSE_SONG (item);
   switch (param_id)
     {
     case PROP_PNET:
-      bse_property_candidate_relabel (pc, _("Available Postprocessors"), _("List of available synthesis 
networks to choose a postprocessor from"));
-      bse_item_gather_items_typed (item, pc->items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
+      pc.label = _("Available Postprocessors");
+      pc.tooltip = _("List of available synthesis networks to choose a postprocessor from");
+      bse_item_gather_items_typed (item, pc.items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
diff --git a/bse/bsesoundfontosc.cc b/bse/bsesoundfontosc.cc
index c592809..64cf4f9 100644
--- a/bse/bsesoundfontosc.cc
+++ b/bse/bsesoundfontosc.cc
@@ -102,8 +102,8 @@ static void  bse_sound_font_osc_get_property  (GObject               *object,
                                                   GValue                *value,
                                                   GParamSpec            *pspec);
 static void     bse_sound_font_osc_get_candidates (BseItem              *item,
-                                                   guint                 param_id,
-                                                   BsePropertyCandidates *pc,
+                                                   uint                  param_id,
+                                                   Bse::PropertyCandidates &pc,
                                                    GParamSpec           *pspec);
 static void     bse_sound_font_osc_context_create (BseSource            *source,
                                                    guint                 context_handle,
@@ -299,17 +299,15 @@ bse_sound_font_osc_get_property (GObject     *object,
 
 
 static void
-bse_sound_font_osc_get_candidates (BseItem               *item,
-                                   guint                  param_id,
-                                   BsePropertyCandidates *pc,
-                                   GParamSpec            *pspec)
+bse_sound_font_osc_get_candidates (BseItem *item, uint param_id, Bse::PropertyCandidates &pc, GParamSpec 
*pspec)
 {
   BseSoundFontOsc *self = BSE_SOUND_FONT_OSC (item);
   switch (param_id)
     {
     case PARAM_PRESET:
-      bse_property_candidate_relabel (pc, _("Available Presets"), _("List of available sound font presets to 
choose as fluid synth preset"));
-      bse_sound_font_repo_list_all_presets (get_sfrepo (self), pc->items);
+      pc.label = _("Available Presets");
+      pc.tooltip = _("List of available sound font presets to choose as fluid synth preset");
+      bse_sound_font_repo_list_all_presets (get_sfrepo (self), pc.items);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
diff --git a/bse/bsesoundfontrepo.cc b/bse/bsesoundfontrepo.cc
index f008087..8db17a8 100644
--- a/bse/bsesoundfontrepo.cc
+++ b/bse/bsesoundfontrepo.cc
@@ -272,21 +272,20 @@ static gboolean
 gather_presets (BseItem    *item,
                 void       *pitems)
 {
-  BseIt3mSeq *items = (BseIt3mSeq *) pitems;
+  Bse::ItemSeq &items = *(Bse::ItemSeq*) pitems;
   if (BSE_IS_SOUND_FONT (item) || BSE_IS_SOUND_FONT_REPO (item))
-    bse_container_forall_items (BSE_CONTAINER (item), gather_presets, items);
+    bse_container_forall_items (BSE_CONTAINER (item), gather_presets, &items);
   else if (BSE_IS_SOUND_FONT_PRESET (item))
-    bse_it3m_seq_append (items, item);
+    items.push_back (item->as<Bse::ItemIfaceP>());
   else
     Bse::warning ("Searching for sound font presets, an unexpected `%s' item was found", 
BSE_OBJECT_TYPE_NAME (item));
   return TRUE;
 }
 
 void
-bse_sound_font_repo_list_all_presets (BseSoundFontRepo *sfrepo,
-                                      BseIt3mSeq       *items)
+bse_sound_font_repo_list_all_presets (BseSoundFontRepo *sfrepo, Bse::ItemSeq &items)
 {
-  gather_presets (BSE_ITEM (sfrepo), items);
+  gather_presets (BSE_ITEM (sfrepo), &items);
 }
 
 std::mutex&
diff --git a/bse/bsesoundfontrepo.hh b/bse/bsesoundfontrepo.hh
index 6ab0fb3..7bb56ea 100644
--- a/bse/bsesoundfontrepo.hh
+++ b/bse/bsesoundfontrepo.hh
@@ -34,7 +34,7 @@ struct BseSoundFontRepoClass : BseSuperClass
 
 /* --- prototypes --- */
 void          bse_sound_font_repo_list_all_presets   (BseSoundFontRepo *sfrepo,
-                                                      BseIt3mSeq       *items);
+                                                      Bse::ItemSeq     &items);
 std::mutex&    bse_sound_font_repo_mutex              (BseSoundFontRepo *sfrepo);
 fluid_synth_t* bse_sound_font_repo_fluid_synth        (BseSoundFontRepo *sfrepo);
 int           bse_sound_font_repo_add_osc            (BseSoundFontRepo *sfrepo,
diff --git a/bse/bsesubsynth.cc b/bse/bsesubsynth.cc
index 0a166d0..c70a13f 100644
--- a/bse/bsesubsynth.cc
+++ b/bse/bsesubsynth.cc
@@ -129,17 +129,15 @@ bse_sub_synth_finalize (GObject *object)
 }
 
 static void
-bse_sub_synth_get_candidates (BseItem               *item,
-                              guint                  param_id,
-                              BsePropertyCandidates *pc,
-                              GParamSpec            *pspec)
+bse_sub_synth_get_candidates (BseItem *item, uint param_id, Bse::PropertyCandidates &pc, GParamSpec *pspec)
 {
   BseSubSynth *self = BSE_SUB_SYNTH (item);
   switch (param_id)
     {
     case PARAM_SNET:
-      bse_property_candidate_relabel (pc, _("Available Synthesizers"), _("List of available synthesis 
networks to choose a sub network from"));
-      bse_item_gather_items_typed (item, pc->items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
+      pc.label = _("Available Synthesizers");
+      pc.tooltip = _("List of available synthesis networks to choose a sub network from");
+      bse_item_gather_items_typed (item, pc.items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
diff --git a/bse/bsetrack.cc b/bse/bsetrack.cc
index 23ecc7e..6e20ceb 100644
--- a/bse/bsetrack.cc
+++ b/bse/bsetrack.cc
@@ -259,10 +259,7 @@ track_uncross_part (BseItem *owner,
 }
 
 static void
-bse_track_get_candidates (BseItem               *item,
-                          guint                  param_id,
-                          BsePropertyCandidates *pc,
-                          GParamSpec            *pspec)
+bse_track_get_candidates (BseItem *item, uint param_id, Bse::PropertyCandidates &pc, GParamSpec *pspec)
 {
   BseTrack *self = BSE_TRACK (item);
   switch (param_id)
@@ -270,34 +267,39 @@ bse_track_get_candidates (BseItem               *item,
       BseProject *project;
       SfiRing *ring;
     case PROP_WAVE:
-      bse_property_candidate_relabel (pc, _("Available Waves"), _("List of available waves to choose as 
track instrument"));
+      pc.label = _("Available Waves");
+      pc.tooltip = _("List of available waves to choose as track instrument");
       project = bse_item_get_project (item);
       if (project)
        {
          BseWaveRepo *wrepo = bse_project_get_wave_repo (project);
-         bse_item_gather_items_typed (BSE_ITEM (wrepo), pc->items, BSE_TYPE_WAVE, BSE_TYPE_WAVE_REPO, FALSE);
+         bse_item_gather_items_typed (BSE_ITEM (wrepo), pc.items, BSE_TYPE_WAVE, BSE_TYPE_WAVE_REPO, FALSE);
        }
       break;
     case PROP_SOUND_FONT_PRESET:
-      bse_property_candidate_relabel (pc, _("Sound Fonts"), _("List of available sound font presets to 
choose as track instrument"));
+      pc.label = _("Sound Fonts");
+      pc.tooltip = _("List of available sound font presets to choose as track instrument");
       project = bse_item_get_project (item);
       if (project)
-       bse_sound_font_repo_list_all_presets (bse_project_get_sound_font_repo (project), pc->items);
+       bse_sound_font_repo_list_all_presets (bse_project_get_sound_font_repo (project), pc.items);
       break;
     case PROP_SNET:
-      bse_property_candidate_relabel (pc, _("Available Synthesizers"), _("List of available synthesis 
networks to choose a track instrument from"));
-      bse_item_gather_items_typed (item, pc->items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
+      pc.label = _("Available Synthesizers");
+      pc.tooltip = _("List of available synthesis networks to choose a track instrument from");
+      bse_item_gather_items_typed (item, pc.items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
       break;
     case PROP_PNET:
-      bse_property_candidate_relabel (pc, _("Available Postprocessors"), _("List of available synthesis 
networks to choose a postprocessor from"));
-      bse_item_gather_items_typed (item, pc->items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
+      pc.label = _("Available Postprocessors");
+      pc.tooltip = _("List of available synthesis networks to choose a postprocessor from");
+      bse_item_gather_items_typed (item, pc.items, BSE_TYPE_CSYNTH, BSE_TYPE_PROJECT, FALSE);
       break;
     case PROP_OUTPUTS:
-      bse_property_candidate_relabel (pc, _("Available Outputs"), _("List of available mixer busses to be 
used as track output"));
-      bse_bus_or_track_list_output_candidates (BSE_ITEM (self), pc->items);
+      pc.label = _("Available Outputs");
+      pc.tooltip = _("List of available mixer busses to be used as track output");
+      bse_bus_or_track_list_output_candidates (BSE_ITEM (self), pc.items);
       /* remove existing outputs */
       for (ring = self->bus_outputs; ring; ring = sfi_ring_walk (ring, self->bus_outputs))
-        bse_it3m_seq_remove (pc->items, (BseItem*) ring->data);
+        vector_erase_element (pc.items, ((BseItem*) ring->data)->as<Bse::ItemIfaceP>());
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
@@ -601,7 +603,11 @@ bse_track_set_property (GObject      *object,
        }
       break;
     case PROP_OUTPUTS:
-      bse_bus_or_track_set_outputs (BSE_ITEM (self), (BseIt3mSeq*) g_value_get_boxed (value));
+      {
+        BseIt3mSeq *i3s = (BseIt3mSeq*) g_value_get_boxed (value);
+        Bse::ItemSeq items = bse_item_seq_from_it3m_seq (i3s);
+        bse_bus_or_track_set_outputs (BSE_ITEM (self), items);
+      }
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (self, param_id, pspec);
diff --git a/bse/bseutils.cc b/bse/bseutils.cc
index a7ef3e5..4abdbb0 100644
--- a/bse/bseutils.cc
+++ b/bse/bseutils.cc
@@ -1,6 +1,7 @@
 // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
 #include "bseutils.hh"
 #include "gsldatautils.hh"
+#include "bseitem.hh"
 
 #include <string.h>
 #include <stdlib.h>
@@ -57,30 +58,22 @@ bse_note_sequence_length (BseNoteSequence *rec)
   return rec->notes->n_notes;
 }
 
-void
-bse_property_candidate_relabel (BsePropertyCandidates *pc,
-                                const gchar           *label,
-                                const gchar           *tooltip)
-{
-  g_free (pc->label);
-  pc->label = g_strdup (label);
-  g_free (pc->tooltip);
-  pc->tooltip = g_strdup (tooltip);
+BseIt3mSeq*
+bse_it3m_seq_from_item_seq (Bse::ItemSeq &items)
+{
+  BseIt3mSeq *i3s = bse_it3m_seq_new();
+  for (auto item : items)
+    bse_it3m_seq_append (i3s, item->as<BseItem*>());
+  return i3s;
 }
 
-void
-bse_it3m_seq_remove (BseIt3mSeq *iseq,
-                     BseItem    *item)
+Bse::ItemSeq
+bse_item_seq_from_it3m_seq (BseIt3mSeq *i3s)
 {
-  guint i;
- restart:
-  for (i = 0; i < iseq->n_items; i++)
-    if (iseq->items[i] == item)
-      {
-        iseq->n_items--;
-        memmove (iseq->items + i, iseq->items + i + 1, (iseq->n_items - i) * sizeof (iseq->items[0]));
-        goto restart;
-      }
+  Bse::ItemSeq items;
+  for (size_t i = 0; i < i3s->n_items; i++)
+    items.push_back (i3s->items[i]->as<Bse::ItemIfaceP>());
+  return items;
 }
 
 SfiRing*
diff --git a/bse/bseutils.hh b/bse/bseutils.hh
index 0d60cf7..82bdf6f 100644
--- a/bse/bseutils.hh
+++ b/bse/bseutils.hh
@@ -15,13 +15,11 @@ Bse::PartControl bse_part_control (uint id, uint tick, Bse::MidiSignal control_t
 void                bse_note_sequence_resize         (BseNoteSequence       *rec,
                                                       guint                  length);
 guint               bse_note_sequence_length         (BseNoteSequence       *rec);
-void                bse_property_candidate_relabel   (BsePropertyCandidates *pc,
-                                                      const gchar           *label,
-                                                      const gchar           *tooltip);
-void                bse_it3m_seq_remove              (BseIt3mSeq            *iseq,
-                                                      BseItem               *item);
 SfiRing*            bse_it3m_seq_to_ring             (BseIt3mSeq            *iseq);
 BseIt3mSeq*         bse_it3m_seq_from_ring           (SfiRing               *ring);
+BseIt3mSeq*         bse_it3m_seq_from_item_seq       (Bse::ItemSeq &items);
+Bse::ItemSeq        bse_item_seq_from_it3m_seq       (BseIt3mSeq *i3s);
+
 
 
 /* --- debugging --- */
diff --git a/bse/bsewaveosc.cc b/bse/bsewaveosc.cc
index d2f35bd..8dce2bc 100644
--- a/bse/bsewaveosc.cc
+++ b/bse/bsewaveosc.cc
@@ -99,22 +99,20 @@ bse_wave_osc_init (BseWaveOsc *self)
 }
 
 static void
-bse_wave_osc_get_candidates (BseItem               *item,
-                             guint                  param_id,
-                             BsePropertyCandidates *pc,
-                             GParamSpec            *pspec)
+bse_wave_osc_get_candidates (BseItem *item, uint param_id, Bse::PropertyCandidates &pc, GParamSpec *pspec)
 {
   BseWaveOsc *self = BSE_WAVE_OSC (item);
   switch (param_id)
     {
       BseProject *project;
     case PARAM_WAVE:
-      bse_property_candidate_relabel (pc, _("Available Waves"), _("List of available waves to choose as 
oscillator source"));
+      pc.label = _("Available Waves");
+      pc.tooltip = _("List of available waves to choose as oscillator source");
       project = bse_item_get_project (item);
       if (project)
         {
           BseWaveRepo *wrepo = bse_project_get_wave_repo (project);
-          bse_item_gather_items_typed (BSE_ITEM (wrepo), pc->items, BSE_TYPE_WAVE, BSE_TYPE_WAVE_REPO, 
FALSE);
+          bse_item_gather_items_typed (BSE_ITEM (wrepo), pc.items, BSE_TYPE_WAVE, BSE_TYPE_WAVE_REPO, FALSE);
         }
       break;
     default:



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]