[med-svn] [aghermann] 44/85: sink abstract common widgets and callbacks dealing with dir-level profiles

andrei zavada hmmr-guest at alioth.debian.org
Thu Sep 26 23:46:29 UTC 2013


This is an automated email from the git hooks/post-receive script.

hmmr-guest pushed a commit to branch master
in repository aghermann.

commit 737f8d54e82acbc9bfcaab99eb6298908327d6fa
Author: Andrei Zavada <johnhommer at gmail.com>
Date:   Wed Sep 18 02:53:15 2013 +0300

    sink abstract common widgets and callbacks dealing with dir-level profiles
---
 upstream/data/sf-patterns.glade                    |   20 +-
 upstream/data/sf-rk1968.glade                      |   19 +-
 upstream/src/aghermann/expdesign/dirlevel.hh       |   11 +-
 upstream/src/aghermann/patterns/patterns.hh        |   18 +-
 upstream/src/aghermann/rk1968/rk1968-profiles.cc   |    3 -
 upstream/src/aghermann/rk1968/rk1968.cc            |   15 +-
 upstream/src/aghermann/rk1968/rk1968.hh            |   49 +++-
 upstream/src/aghermann/ui/Makefile.am              |    2 +
 .../src/aghermann/ui/dirlevel-storable-adapter.hh  |  115 ++++++++
 .../src/aghermann/ui/dirlevel-storable-adapter.ii  |  310 ++++++++++++++++++++
 upstream/src/aghermann/ui/sf/Makefile.am           |    3 +-
 .../src/aghermann/ui/sf/d/artifacts-construct.cc   |    1 +
 .../src/aghermann/ui/sf/d/patterns-construct.cc    |  170 -----------
 upstream/src/aghermann/ui/sf/d/patterns-draw.cc    |   34 +--
 .../src/aghermann/ui/sf/d/patterns-profiles.cc     |  118 +-------
 .../src/aghermann/ui/sf/d/patterns-profiles_cb.cc  |  123 ++------
 upstream/src/aghermann/ui/sf/d/patterns.cc         |  232 +++++++++++----
 upstream/src/aghermann/ui/sf/d/patterns.hh         |  202 ++++++-------
 upstream/src/aghermann/ui/sf/d/patterns_cb.cc      |   12 +-
 .../src/aghermann/ui/sf/d/phasediff-construct.cc   |    2 +-
 upstream/src/aghermann/ui/sf/d/rk1968-construct.cc |   65 ----
 upstream/src/aghermann/ui/sf/d/rk1968-profiles.cc  |  108 +------
 .../src/aghermann/ui/sf/d/rk1968-profiles_cb.cc    |   93 ++++++
 upstream/src/aghermann/ui/sf/d/rk1968.cc           |   64 +++-
 upstream/src/aghermann/ui/sf/d/rk1968.hh           |   80 +++--
 upstream/src/aghermann/ui/sf/d/rk1968_cb.cc        |   68 ++++-
 26 files changed, 1103 insertions(+), 834 deletions(-)

diff --git a/upstream/data/sf-patterns.glade b/upstream/data/sf-patterns.glade
index 3060cbe..3b4dc57 100644
--- a/upstream/data/sf-patterns.glade
+++ b/upstream/data/sf-patterns.glade
@@ -458,7 +458,7 @@
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <child>
-                      <object class="GtkComboBox" id="eSFFDPatternList">
+                      <object class="GtkComboBox" id="eSFFDProfileList">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
                       </object>
@@ -1394,7 +1394,7 @@ on individual parameters</property>
       <action-widget response="-1">bSFFDDismiss</action-widget>
     </action-widgets>
   </object>
-  <object class="GtkDialog" id="wSFFDPatternSave">
+  <object class="GtkDialog" id="wSFFDProfileSave">
     <property name="width_request">200</property>
     <property name="can_focus">False</property>
     <property name="border_width">5</property>
@@ -1425,7 +1425,7 @@ on individual parameters</property>
             <property name="label_xalign">0</property>
             <property name="shadow_type">none</property>
             <child>
-              <object class="GtkEntry" id="eSFFDPatternSaveName">
+              <object class="GtkEntry" id="eSFFDProfileSaveName">
                 <property name="width_request">130</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
@@ -1471,7 +1471,7 @@ on individual parameters</property>
                 <property name="orientation">vertical</property>
                 <property name="spacing">3</property>
                 <child>
-                  <object class="GtkRadioButton" id="eSFFDPatternSaveOriginUser">
+                  <object class="GtkRadioButton" id="eSFFDProfileSaveOriginUser">
                     <property name="label" translatable="yes">_User</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
@@ -1488,7 +1488,7 @@ on individual parameters</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkRadioButton" id="eSFFDPatternSaveOriginExperiment">
+                  <object class="GtkRadioButton" id="eSFFDProfileSaveOriginExperiment">
                     <property name="label" translatable="yes">_Experiment</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
@@ -1496,7 +1496,7 @@ on individual parameters</property>
                     <property name="use_underline">True</property>
                     <property name="xalign">0</property>
                     <property name="draw_indicator">True</property>
-                    <property name="group">eSFFDPatternSaveOriginUser</property>
+                    <property name="group">eSFFDProfileSaveOriginUser</property>
                   </object>
                   <packing>
                     <property name="expand">False</property>
@@ -1505,7 +1505,7 @@ on individual parameters</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkRadioButton" id="eSFFDPatternSaveOriginSubject">
+                  <object class="GtkRadioButton" id="eSFFDProfileSaveOriginSubject">
                     <property name="label" translatable="yes">_Subject</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
@@ -1513,7 +1513,7 @@ on individual parameters</property>
                     <property name="use_underline">True</property>
                     <property name="xalign">0</property>
                     <property name="draw_indicator">True</property>
-                    <property name="group">eSFFDPatternSaveOriginUser</property>
+                    <property name="group">eSFFDProfileSaveOriginUser</property>
                   </object>
                   <packing>
                     <property name="expand">False</property>
@@ -1559,7 +1559,7 @@ on individual parameters</property>
               </packing>
             </child>
             <child>
-              <object class="GtkButton" id="bSFFDPatternSaveOK">
+              <object class="GtkButton" id="bSFFDProfileSaveOK">
                 <property name="label">gtk-ok</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
@@ -1588,7 +1588,7 @@ on individual parameters</property>
     </child>
     <action-widgets>
       <action-widget response="-6">button1</action-widget>
-      <action-widget response="-5">bSFFDPatternSaveOK</action-widget>
+      <action-widget response="-5">bSFFDProfileSaveOK</action-widget>
     </action-widgets>
   </object>
   <object class="GtkSizeGroup" id="zButton">
diff --git a/upstream/data/sf-rk1968.glade b/upstream/data/sf-rk1968.glade
index 1be3f98..8c21d9c 100644
--- a/upstream/data/sf-rk1968.glade
+++ b/upstream/data/sf-rk1968.glade
@@ -57,7 +57,7 @@
                 <property name="orientation">vertical</property>
                 <property name="homogeneous">True</property>
                 <child>
-                  <object class="GtkButton" id="bSFRKRun">
+                  <object class="GtkButton" id="bSFRKTry">
                     <property name="label" translatable="yes">Try</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
@@ -259,6 +259,9 @@
                       <placeholder/>
                     </child>
                     <child>
+                      <placeholder/>
+                    </child>
+                    <child>
                       <object class="GtkSpinButton" id="eSFRKNremThetaDeltaRatio">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
@@ -401,7 +404,7 @@
                 <property name="orientation">vertical</property>
                 <property name="spacing">3</property>
                 <child>
-                  <object class="GtkRadioButton" id="eSFFDPatternSaveOriginUser">
+                  <object class="GtkRadioButton" id="eSFRKProfileSaveOriginUser">
                     <property name="label" translatable="yes">_User</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
@@ -418,7 +421,7 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkRadioButton" id="eSFFDPatternSaveOriginExperiment">
+                  <object class="GtkRadioButton" id="eSFRKProfileSaveOriginExperiment">
                     <property name="label" translatable="yes">_Experiment</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
@@ -426,7 +429,7 @@
                     <property name="use_underline">True</property>
                     <property name="xalign">0</property>
                     <property name="draw_indicator">True</property>
-                    <property name="group">eSFFDPatternSaveOriginUser</property>
+                    <property name="group">eSFRKProfileSaveOriginUser</property>
                   </object>
                   <packing>
                     <property name="expand">False</property>
@@ -435,7 +438,7 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkRadioButton" id="eSFFDPatternSaveOriginSubject">
+                  <object class="GtkRadioButton" id="eSFRKProfileSaveOriginSubject">
                     <property name="label" translatable="yes">_Subject</property>
                     <property name="visible">True</property>
                     <property name="can_focus">True</property>
@@ -443,7 +446,7 @@
                     <property name="use_underline">True</property>
                     <property name="xalign">0</property>
                     <property name="draw_indicator">True</property>
-                    <property name="group">eSFFDPatternSaveOriginUser</property>
+                    <property name="group">eSFRKProfileSaveOriginUser</property>
                   </object>
                   <packing>
                     <property name="expand">False</property>
@@ -489,7 +492,7 @@
               </packing>
             </child>
             <child>
-              <object class="GtkButton" id="bSFFDPatternSaveOK">
+              <object class="GtkButton" id="bSFRKProfileSaveOK">
                 <property name="label">gtk-ok</property>
                 <property name="visible">True</property>
                 <property name="can_focus">True</property>
@@ -518,7 +521,7 @@
     </child>
     <action-widgets>
       <action-widget response="-6">button1</action-widget>
-      <action-widget response="-5">bSFFDPatternSaveOK</action-widget>
+      <action-widget response="-5">bSFRKProfileSaveOK</action-widget>
     </action-widgets>
   </object>
 </interface>
diff --git a/upstream/src/aghermann/expdesign/dirlevel.hh b/upstream/src/aghermann/expdesign/dirlevel.hh
index 33fe23d..65c575c 100644
--- a/upstream/src/aghermann/expdesign/dirlevel.hh
+++ b/upstream/src/aghermann/expdesign/dirlevel.hh
@@ -61,8 +61,15 @@ class CStorablePPack {
                 saved (false)
                 {} // don't load, defer until config_keys_* are connected
 
-        CStorablePPack (const CStorablePPack&) = delete;  // because of config_keys_*
-        CStorablePPack& operator=( const CStorablePPack&) = delete;  // and because we cannot have identical profiles in tree
+        CStorablePPack (const CStorablePPack& rv)   // is ok, just leave alone the config_keys_*
+              : subdir (rv.subdir),
+                name (rv.name),
+                level (rv.level),
+                level_id (rv.level_id),
+                ED (rv.ED),
+                saved (rv.saved)
+                {}
+//        CStorablePPack& operator=( const CStorablePPack&) = delete;  // and because we cannot have identical profiles in tree
 
         string  subdir,
                 name;
diff --git a/upstream/src/aghermann/patterns/patterns.hh b/upstream/src/aghermann/patterns/patterns.hh
index 793ee80..6407f42 100644
--- a/upstream/src/aghermann/patterns/patterns.hh
+++ b/upstream/src/aghermann/patterns/patterns.hh
@@ -123,7 +123,7 @@ struct SPattern
                 {}
 
         explicit SPattern<T> (const SPattern<T>& rv)
-              : CStorablePPack (common_subdir, rv.name + " (dup)", TExpDirLevel::transient, rv.ED, rv.level_id),
+              : CStorablePPack (rv),
                 thing      (rv.thing),
                 samplerate (rv.samplerate),
                 context    (rv.context),
@@ -133,7 +133,7 @@ struct SPattern
                         // assign_keys();
                 }
         explicit SPattern<T> (SPattern<T>&& rv)
-              : CStorablePPack (common_subdir, move(rv.name), rv.level_, rv.ED, move(rv.level_id)),
+              : CStorablePPack (common_subdir, move(rv.name), rv.level, rv.ED, move(rv.level_id)),
                 thing      (move(rv.thing)),
                 samplerate (rv.samplerate),
                 context    (rv.context),
@@ -150,6 +150,18 @@ struct SPattern
                 }
 
         SPattern&
+        operator=( const SPattern<T>& rv)
+                {
+                        thing.resize(rv.thing.size());
+                        thing      = rv.thing;
+                        samplerate = rv.samplerate;
+                        context    = rv.context;
+                        Pp       = rv.Pp;
+                        criteria = rv.criteria;
+
+                        return *this;
+                }
+        SPattern&
         operator=( SPattern<T>&& rv)
                 {
                         swap       (thing, rv.thing);
@@ -158,8 +170,6 @@ struct SPattern
                         swap       (Pp, rv.Pp);
                         swap       (criteria, rv.criteria);
 
-                        // assign_keys(); // have specialized save/load
-
                         return *this;
                 }
 
diff --git a/upstream/src/aghermann/rk1968/rk1968-profiles.cc b/upstream/src/aghermann/rk1968/rk1968-profiles.cc
index 44b0dfd..bbe98f8 100644
--- a/upstream/src/aghermann/rk1968/rk1968-profiles.cc
+++ b/upstream/src/aghermann/rk1968/rk1968-profiles.cc
@@ -14,7 +14,6 @@
 
 #include "common/fs.hh"
 #include "common/config-validate.hh"
-#include "aghermann/expdesign/subject.hh"
 #include "aghermann/expdesign/expdesign.hh"
 
 #include "rk1968.hh"
@@ -24,8 +23,6 @@ using namespace std;
 using namespace agh::rk1968;
 
 
-
-
 int
 CScoreAssistant::
 delete_file()
diff --git a/upstream/src/aghermann/rk1968/rk1968.cc b/upstream/src/aghermann/rk1968/rk1968.cc
index 8888336..12960cc 100644
--- a/upstream/src/aghermann/rk1968/rk1968.cc
+++ b/upstream/src/aghermann/rk1968/rk1968.cc
@@ -26,16 +26,23 @@ using namespace std;
 using namespace agh::rk1968;
 
 
+
+using agh::confval::SValidator;
+
 CScoreAssistant::
 CScoreAssistant (const string& name_,
-                 agh::TExpDirLevel level_, agh::CExpDesign& ED_, const agh::SExpDirLevelId& level_id_,
-                 const SScoreAssistantPPack& Pp_)
-      : CStorablePPack (".rk1968", name_, level_, ED_, level_id_),
-        Pp (Pp_)
+                 TExpDirLevel level_, CExpDesign& ED_, const SExpDirLevelId& level_id_)
+      : CStorablePPack (common_subdir, name_, level_, ED_, level_id_)
 {
+        config_keys_g.assign({
+                SValidator<double>("nrem3_delta_theta_ratio", &Pp.nrem3_delta_theta_ratio),
+        });
+
+        load();
 }
 
 
+
 int
 CScoreAssistant::
 score( agh::SEpisode& E)
diff --git a/upstream/src/aghermann/rk1968/rk1968.hh b/upstream/src/aghermann/rk1968/rk1968.hh
index 1c4dab2..fcd173e 100644
--- a/upstream/src/aghermann/rk1968/rk1968.hh
+++ b/upstream/src/aghermann/rk1968/rk1968.hh
@@ -23,19 +23,60 @@ namespace rk1968 {
 struct SScoreAssistantPPack {
         double  nrem3_delta_theta_ratio;
 
-        SScoreAssistantPPack (const SScoreAssistantPPack&) = default;
         SScoreAssistantPPack ()
               : nrem3_delta_theta_ratio (1.5)
                 {}
+        explicit SScoreAssistantPPack (const SScoreAssistantPPack&) = default;
+        SScoreAssistantPPack& operator=( const SScoreAssistantPPack&) = default;
+        SScoreAssistantPPack& operator=( SScoreAssistantPPack&&) = default;
+
+        bool operator==( const SScoreAssistantPPack& rv)
+                {
+                        return nrem3_delta_theta_ratio == rv.nrem3_delta_theta_ratio;
+                }
 };
 
 class CScoreAssistant
   : public CStorablePPack {
 
     public:
+        static constexpr const char* common_subdir = ".rk1968/";
+
         CScoreAssistant (const string& name_,
-                         TExpDirLevel, CExpDesign&, const SExpDirLevelId&,
-                         const SScoreAssistantPPack&);
+                         TExpDirLevel, CExpDesign&, const SExpDirLevelId&);
+        explicit CScoreAssistant (const CScoreAssistant& rv)
+              : CStorablePPack (common_subdir, rv.name + " (dup)", TExpDirLevel::transient, rv.ED, rv.level_id),
+                Pp (rv.Pp)
+                {
+                        // assign_keys();
+                }
+        explicit CScoreAssistant (CExpDesign& ED_, const SExpDirLevelId& level_id_)
+              : CStorablePPack (common_subdir, "(unnamed)", TExpDirLevel::transient, ED_, level_id_)
+                {}
+
+       ~CScoreAssistant ()
+                {
+                        save();
+                }
+
+        CScoreAssistant&
+        operator=( CScoreAssistant&& rv)
+                {
+                        Pp = move(rv.Pp);
+                        return *this;
+                }
+        CScoreAssistant&
+        operator=( const CScoreAssistant& rv)
+                {
+                        Pp = rv.Pp;
+                        return *this;
+                }
+
+        bool
+        operator==( const CScoreAssistant& rv)
+                {
+                        return Pp == rv.Pp;
+                }
 
         int score( agh::SEpisode&);
 
@@ -45,8 +86,6 @@ class CScoreAssistant
                 Pp;
 };
 
-list<CScoreAssistant>
-load_profiles_from_location( const string& loc, agh::TExpDirLevel);
 
 } // namespace rk1968
 } // namespace agh
diff --git a/upstream/src/aghermann/ui/Makefile.am b/upstream/src/aghermann/ui/Makefile.am
index 65d36d8..64185a6 100644
--- a/upstream/src/aghermann/ui/Makefile.am
+++ b/upstream/src/aghermann/ui/Makefile.am
@@ -10,6 +10,8 @@ noinst_LIBRARIES := liba.a
 
 liba_a_SOURCES := \
 	forward-decls.hh \
+	dirlevel-storable-adapter.hh \
+	dirlevel-storable-adapter.ii \
 	globals.cc \
 	globals.hh \
 	misc.cc \
diff --git a/upstream/src/aghermann/ui/dirlevel-storable-adapter.hh b/upstream/src/aghermann/ui/dirlevel-storable-adapter.hh
new file mode 100644
index 0000000..d555801
--- /dev/null
+++ b/upstream/src/aghermann/ui/dirlevel-storable-adapter.hh
@@ -0,0 +1,115 @@
+/*
+ *       File name:  aghermann/ui/dirlevel-storable-adapter.hh
+ *         Project:  Aghermann
+ *          Author:  Andrei Zavada <johnhommer at gmail.com>
+ * Initial version:  2013-09-15
+ *
+ *         Purpose:  widget class for handling dirlevel storable profiles
+ *
+ *         License:  GPL
+ */
+
+#ifndef AGH_AGHERMANN_UI_DIRLEVEL_STORABLE_ADAPTER_H_
+#define AGH_AGHERMANN_UI_DIRLEVEL_STORABLE_ADAPTER_H_
+
+#include "aghermann/expdesign/dirlevel.hh"
+#include "aghermann/expdesign/expdesign.hh"
+#include "aghermann/ui/misc.hh"
+#include "aghermann/ui/mw/mw.hh"
+
+#if HAVE_CONFIG_H && !defined(VERSION)
+#  include "config.h"
+#endif
+
+using namespace std;
+
+namespace agh {
+namespace ui {
+
+template <class Storable>
+class SDirlevelStorableAdapter {
+
+    public:
+        SDirlevelStorableAdapter<Storable> (
+                agh::CExpDesign&, const agh::SExpDirLevelId&,
+                GtkListStore*&, GtkComboBox*&, gulong&,
+                GtkButton*&, GtkButton*&, GtkButton*&,
+                GtkDialog*&, GtkEntry*&, GtkToggleButton*&, GtkToggleButton*&, GtkToggleButton*&, GtkButton*&);
+
+        agh::CExpDesign&
+               ED;
+        agh::SExpDirLevelId
+               level_id;
+
+        list<Storable>
+                profiles;
+        typename list<Storable>::iterator
+                current_profile;
+        typename list<Storable>::iterator
+        profile_by_idx( size_t);
+
+        void load_profiles();
+        void save_profiles();
+        void discard_current_profile();
+        void populate_combo();
+        void set_profile_manage_buttons_visibility();
+
+        Storable
+                Pp2;
+
+        SUIVarCollection
+                W_V;
+        void atomic_up()
+                {
+                        suppress_w_v = true;
+                        W_V.up();
+                        suppress_w_v = false;
+                }
+        bool    suppress_w_v;
+
+        GtkListStore
+                *&mXProfiles;
+
+        GtkComboBox
+                *&eXProfileList;
+        gulong  &eXProfileList_changed_cb_handler_id;
+        GtkButton
+                *&bXProfileSave,
+                *&bXProfileRevert,
+                *&bXProfileDiscard;
+        GtkDialog
+                *&wXProfileSaveName;
+        GtkEntry
+                *&eXProfileSaveName;
+        GtkToggleButton
+                *&eXProfileSaveOriginSubject,
+                *&eXProfileSaveOriginExperiment,
+                *&eXProfileSaveOriginUser;
+        GtkButton
+                *&bXProfileSaveOK;
+
+        void eXProfileList_changed_cb();
+        void bXProfileSave_clicked_cb();
+        void bXProfileDiscard_clicked_cb();
+        void bXProfileRevert_clicked_cb();
+        void eXProfileSaveName_changed_cb();
+        void eX_any_profile_origin_toggled_cb();
+
+    private:
+        void check_profile_name_save_button_label();
+};
+
+}}
+
+
+#include "dirlevel-storable-adapter.ii"
+
+
+
+#endif
+
+// Local Variables:
+// Mode: c++
+// indent-tabs-mode: nil
+// tab-width: 8
+// End:
diff --git a/upstream/src/aghermann/ui/dirlevel-storable-adapter.ii b/upstream/src/aghermann/ui/dirlevel-storable-adapter.ii
new file mode 100644
index 0000000..2ef72e6
--- /dev/null
+++ b/upstream/src/aghermann/ui/dirlevel-storable-adapter.ii
@@ -0,0 +1,310 @@
+/*
+ *       File name:  aghermann/ui/dirlevel-storable-adapter.ii
+ *         Project:  Aghermann
+ *          Author:  Andrei Zavada <johnhommer at gmail.com>
+ * Initial version:  2013-09-15
+ *
+ *         Purpose:  
+ *
+ *         License:  GPL
+ */
+
+#include <tuple>
+
+using namespace std;
+using namespace agh::ui;
+
+
+namespace agh {
+namespace ui {
+
+
+template <class Storable>
+SDirlevelStorableAdapter<Storable>::
+SDirlevelStorableAdapter (agh::CExpDesign& ED_, const agh::SExpDirLevelId& level_id_,
+                          GtkListStore*& mXProfiles_, GtkComboBox*& eXProfileList_, gulong& eXProfileList_changed_cb_handler_id_,
+                          GtkButton*& bXProfileSave_, GtkButton*& bXProfileRevert_, GtkButton*& bXProfileDiscard_,
+                          GtkDialog*& wXProfileSaveName_, GtkEntry*& eXProfileSaveName_, GtkToggleButton*& eXProfileSaveOriginSubject_, GtkToggleButton*& eXProfileSaveOriginExperiment_, GtkToggleButton*& eXProfileSaveOriginUser_, GtkButton*& bXProfileSaveOK_)
+      : ED (ED_),
+        level_id (level_id_),
+        Pp2 (ED_, level_id_),
+        mXProfiles (mXProfiles_),
+        eXProfileList (eXProfileList_),
+        eXProfileList_changed_cb_handler_id (eXProfileList_changed_cb_handler_id_),
+        bXProfileSave (bXProfileSave_),
+        bXProfileRevert (bXProfileRevert_),
+        bXProfileDiscard (bXProfileDiscard_),
+        wXProfileSaveName (wXProfileSaveName_),
+        eXProfileSaveName (eXProfileSaveName_),
+        eXProfileSaveOriginSubject (eXProfileSaveOriginSubject_),
+        eXProfileSaveOriginExperiment (eXProfileSaveOriginExperiment_),
+        eXProfileSaveOriginUser (eXProfileSaveOriginUser_),
+        bXProfileSaveOK (bXProfileSaveOK_)
+{
+        // connecting all gtk widgets is handled by the derived class
+}
+
+template <class Storable>
+typename list<Storable>::iterator
+SDirlevelStorableAdapter<Storable>::
+profile_by_idx( size_t idx)
+{
+        size_t i = 0;
+        for ( auto I = profiles.begin(); I != profiles.end(); ++I )
+                if ( i == idx )
+                        return I;
+                else
+                        ++i;
+        throw invalid_argument ("Current profile index invalid");
+}
+
+
+
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+load_profiles()
+{
+        profiles.clear();
+
+        using namespace agh;
+        for ( auto A : {TExpDirLevel::system, TExpDirLevel::user, TExpDirLevel::experiment, TExpDirLevel::subject} )
+                profiles.splice(
+                        profiles.end(),
+                        load_profiles_from_location<Storable>(
+                                Storable::common_subdir,
+                                A, ED, level_id));
+
+        current_profile = profiles.end();
+}
+
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+populate_combo()
+{
+        g_signal_handler_block( eXProfileList, eXProfileList_changed_cb_handler_id);
+        gtk_list_store_clear( mXProfiles);
+
+        if ( not profiles.empty() ) {
+                GtkTreeIter iter, current_profile_iter;
+                for ( auto I = profiles.begin(); I != profiles.end(); ++I ) {
+                        gtk_list_store_append(
+                                mXProfiles, &iter);
+                        gtk_list_store_set(
+                                mXProfiles, &iter,
+                                0, snprintf_buf( "%s %s", agh::exp_dir_level_s(I->level), I->name.c_str()),
+                                -1);
+                        if ( I == current_profile )
+                                current_profile_iter = iter;
+                }
+
+                gtk_combo_box_set_active_iter( eXProfileList, &current_profile_iter);
+        } else
+                gtk_combo_box_set_active_iter( eXProfileList, NULL);
+
+        g_signal_handler_unblock( eXProfileList, eXProfileList_changed_cb_handler_id);
+}
+
+
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+save_profiles()
+{
+        for ( auto& P : profiles )
+                P.save();
+}
+
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+discard_current_profile()
+{
+        if ( current_profile == profiles.end() )
+                return;
+
+        auto todelete = current_profile;
+        current_profile = next(current_profile);
+        todelete->delete_file();
+        profiles.erase( todelete);
+}
+
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+set_profile_manage_buttons_visibility()
+{
+        bool    have_active  = current_profile != profiles.end(),
+                is_transient = have_active && current_profile->level == agh::TExpDirLevel::transient,
+                is_modified  = have_active && not (*current_profile == Pp2);
+        //printf( "active %d %s %d\n", have_active, have_active ? agh::exp_dir_level_s(current_profile->level) : "-", have_active ? not (*current_profile == Pp2) : -1);
+        gtk_widget_set_visible( (GtkWidget*)bXProfileSave, have_active);
+        gtk_widget_set_visible( (GtkWidget*)bXProfileRevert, have_active and not is_transient and is_modified);
+        gtk_widget_set_visible( (GtkWidget*)bXProfileDiscard, have_active and not is_transient);
+        gtk_widget_set_sensitive( (GtkWidget*)eXProfileList, not is_modified);
+}
+
+
+
+// callback shims
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+eXProfileList_changed_cb()
+{
+        gint ci = gtk_combo_box_get_active( eXProfileList);
+        if ( ci != -1 ) {
+                current_profile = profile_by_idx(ci);
+                Pp2 = *current_profile;
+                atomic_up();
+                set_profile_manage_buttons_visibility();
+        } else {
+                current_profile = profiles.end();
+        }
+}
+
+
+
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+bXProfileSave_clicked_cb()
+{
+        g_signal_emit_by_name( eXProfileSaveName, "changed");
+
+        if ( GTK_RESPONSE_OK == gtk_dialog_run( wXProfileSaveName) ) {
+                using namespace agh;
+
+                // replace unnamed, else check if one exists, else add new
+                auto this_name = gtk_entry_get_text( eXProfileSaveName);
+                auto this_level =
+                        gtk_toggle_button_get_active( eXProfileSaveOriginSubject)
+                        ? TExpDirLevel::subject
+                        : gtk_toggle_button_get_active( eXProfileSaveOriginExperiment)
+                        ? TExpDirLevel::experiment
+                        : TExpDirLevel::user;
+
+                auto overwriting =
+                        find_if( profiles.begin(), profiles.end(),
+                                 [&] ( const Storable& P) -> bool
+                                 { return P.name == this_name && P.level == this_level; });
+                auto& P =
+                        (overwriting != profiles.end())
+                        ? *overwriting
+                        : (current_profile->level == agh::TExpDirLevel::transient)
+                        ? * current_profile
+                        : *(current_profile = profiles.insert(current_profile, *current_profile));
+
+                P = Pp2;  // except that it has new name and level
+                P.name = this_name;
+                P.level = this_level;
+
+                populate_combo();
+                set_profile_manage_buttons_visibility();
+        }
+}
+
+
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+check_profile_name_save_button_label()
+{
+        gtk_widget_set_sensitive(
+                (GtkWidget*)bXProfileSaveOK,
+                gtk_entry_get_text_length( eXProfileSaveName) > 0);
+
+        using namespace agh;
+        auto this_name = gtk_entry_get_text( eXProfileSaveName);
+        auto this_level = gtk_toggle_button_get_active( eXProfileSaveOriginSubject)
+                        ? TExpDirLevel::subject
+                        : gtk_toggle_button_get_active( eXProfileSaveOriginExperiment)
+                        ? TExpDirLevel::experiment
+                        : TExpDirLevel::user;
+
+        bool overwriting =
+                find_if( profiles.begin(), profiles.end(),
+                         [&] ( const Storable& P) -> bool
+                         { return P.name == this_name && P.level == this_level; })
+                != profiles.end();
+        gtk_button_set_label(
+                bXProfileSaveOK,
+                overwriting ? "Overwrite" : "Save");
+}
+
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+eXProfileSaveName_changed_cb()
+{
+        check_profile_name_save_button_label();
+}
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+eX_any_profile_origin_toggled_cb()
+{
+        check_profile_name_save_button_label();
+}
+
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+bXProfileDiscard_clicked_cb()
+{
+        gint ci = gtk_combo_box_get_active( eXProfileList);
+
+        assert ( current_profile != profiles.end() );
+        assert ( ci != -1 );
+        assert ( ci < (int)profiles.size() );
+
+        discard_current_profile();
+
+        if ( not profiles.empty() ) {
+                Pp2 = *current_profile;
+
+                atomic_up();
+        }
+
+        populate_combo();
+        set_profile_manage_buttons_visibility();
+}
+
+
+template <class Storable>
+void
+SDirlevelStorableAdapter<Storable>::
+bXProfileRevert_clicked_cb()
+{
+        assert ( current_profile != profiles.end() );
+        assert ( current_profile->level != agh::TExpDirLevel::transient );
+
+        Pp2 = *current_profile;
+
+        atomic_up();
+
+        set_profile_manage_buttons_visibility();
+}
+
+
+}}
+
+
+// Local Variables:
+// Mode: c++
+// indent-tabs-mode: nil
+// tab-width: 8
+// c-basic-offset: 8
+// End:
diff --git a/upstream/src/aghermann/ui/sf/Makefile.am b/upstream/src/aghermann/ui/sf/Makefile.am
index 7737f4a..e1a16e7 100644
--- a/upstream/src/aghermann/ui/sf/Makefile.am
+++ b/upstream/src/aghermann/ui/sf/Makefile.am
@@ -39,7 +39,6 @@ liba_a_SOURCES := \
 	d/filters_cb.cc \
 	d/patterns.hh \
 	d/patterns.cc \
-	d/patterns-construct.cc \
 	d/patterns-draw.cc \
 	d/patterns-profiles.cc \
 	d/patterns_cb.cc \
@@ -50,6 +49,6 @@ liba_a_SOURCES := \
 	d/phasediff_cb.cc \
 	d/rk1968.hh \
 	d/rk1968.cc \
-	d/rk1968-construct.cc \
 	d/rk1968-profiles.cc \
+	d/rk1968-profiles_cb.cc \
 	d/rk1968_cb.cc
diff --git a/upstream/src/aghermann/ui/sf/d/artifacts-construct.cc b/upstream/src/aghermann/ui/sf/d/artifacts-construct.cc
index a7115d0..cbf986b 100644
--- a/upstream/src/aghermann/ui/sf/d/artifacts-construct.cc
+++ b/upstream/src/aghermann/ui/sf/d/artifacts-construct.cc
@@ -82,6 +82,7 @@ SArtifactsDialogWidgets::
 ~SArtifactsDialogWidgets ()
 {
         gtk_widget_destroy( (GtkWidget*)wSFAD);
+        g_object_unref( (GObject*)mSFADProfiles);
         g_object_unref( (GObject*)builder);
 }
 
diff --git a/upstream/src/aghermann/ui/sf/d/patterns-construct.cc b/upstream/src/aghermann/ui/sf/d/patterns-construct.cc
deleted file mode 100644
index 3143c2a..0000000
--- a/upstream/src/aghermann/ui/sf/d/patterns-construct.cc
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- *       File name:  aghermann/ui/sf/d/patterns-construct.cc
- *         Project:  Aghermann
- *          Author:  Andrei Zavada <johnhommer at gmail.com>
- * Initial version:  2013-01-24
- *
- *         Purpose:  scoring facility Patterns widget construction
- *
- *         License:  GPL
- */
-
-#include <stdexcept>
-
-#include "aghermann/ui/sf/channel.hh"
-#include "patterns.hh"
-
-using namespace std;
-using namespace agh::ui;
-
-SPatternsDialogWidgets::
-SPatternsDialogWidgets (SScoringFacility& SF)
-{
-        builder = gtk_builder_new();
-        if ( !gtk_builder_add_from_resource( builder, "/org/gtk/aghermann/sf-patterns.glade", NULL) )
-                throw runtime_error( "Failed to load SF::patterns glade resource");
-        gtk_builder_connect_signals( builder, NULL);
-
-        mSFFDPatterns =
-                gtk_list_store_new( 1, G_TYPE_STRING);
-        mSFFDChannels =
-                gtk_list_store_new( 1, G_TYPE_STRING);
-
-        if ( !AGH_GBGETOBJ (GtkDialog,         wSFFD) ||
-             !AGH_GBGETOBJ (GtkDrawingArea,    daSFFDThing) ||
-             !AGH_GBGETOBJ (GtkScrolledWindow, swSFFDThing) ||
-             !AGH_GBGETOBJ (GtkDrawingArea,    daSFFDField) ||
-             !AGH_GBGETOBJ (GtkMenuBar,        iibSFFDMenu) ||
-             !AGH_GBGETOBJ (GtkMenu,           iiSFFDField) ||
-             !AGH_GBGETOBJ (GtkMenu,           iiSFFDFieldProfileTypes) ||
-             !AGH_GBGETOBJ (GtkCheckMenuItem,  iSFFDFieldDrawMatchIndex) ||
-             !AGH_GBGETOBJ (GtkRadioMenuItem,  iSFFDFieldProfileTypeRaw) ||
-             !AGH_GBGETOBJ (GtkRadioMenuItem,  iSFFDFieldProfileTypePSD) ||
-             !AGH_GBGETOBJ (GtkRadioMenuItem,  iSFFDFieldProfileTypeMC)  ||
-             !AGH_GBGETOBJ (GtkRadioMenuItem,  iSFFDFieldProfileTypeSWU) ||
-             !AGH_GBGETOBJ (GtkMenuItem,       iSFFDMarkPhasicEventSpindles) ||
-             !AGH_GBGETOBJ (GtkMenuItem,       iSFFDMarkPhasicEventKComplexes) ||
-             !AGH_GBGETOBJ (GtkMenuItem,       iSFFDMarkPlain) ||
-             !AGH_GBGETOBJ (GtkScrolledWindow, swSFFDField) ||
-             !AGH_GBGETOBJ (GtkTable,          cSFFDSearchButton) ||
-             !AGH_GBGETOBJ (GtkTable,          cSFFDAgainButton) ||
-             !AGH_GBGETOBJ (GtkBox,            cSFFDSearching) ||
-             !AGH_GBGETOBJ (GtkTable,          cSFFDParameters) ||
-             !AGH_GBGETOBJ (GtkTable,          cSFFDCriteria) ||
-             !AGH_GBGETOBJ (GtkButton,         bSFFDSearch) ||
-             !AGH_GBGETOBJ (GtkButton,         bSFFDAgain) ||
-             !AGH_GBGETOBJ (GtkButton,         bSFFDProfileSave) ||
-             !AGH_GBGETOBJ (GtkButton,         bSFFDProfileDiscard) ||
-             !AGH_GBGETOBJ (GtkButton,         bSFFDProfileRevert) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDEnvTightness) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDBandPassOrder) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDBandPassFrom) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDBandPassUpto) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDDZCDFStep) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDDZCDFSigma) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDDZCDFSmooth) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDParameterA) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDParameterB) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDParameterC) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDParameterD) ||
-             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDIncrement) ||
-             !AGH_GBGETOBJ (GtkHBox,           cSFFDLabelBox) ||
-             !AGH_GBGETOBJ (GtkLabel,          lSFFDParametersBrief) ||
-             !AGH_GBGETOBJ (GtkLabel,          lSFFDFoundInfo) ||
-             !AGH_GBGETOBJ (GtkComboBox,       eSFFDPatternList) ||
-             !AGH_GBGETOBJ (GtkComboBox,       eSFFDChannel) ||
-             !AGH_GBGETOBJ (GtkDialog,         wSFFDPatternSave) ||
-             !AGH_GBGETOBJ (GtkEntry,          eSFFDPatternSaveName) ||
-             !AGH_GBGETOBJ (GtkToggleButton,   eSFFDPatternSaveOriginSubject) ||
-             !AGH_GBGETOBJ (GtkToggleButton,   eSFFDPatternSaveOriginExperiment) ||
-             !AGH_GBGETOBJ (GtkToggleButton,   eSFFDPatternSaveOriginUser) ||
-             !AGH_GBGETOBJ (GtkButton,         bSFFDPatternSaveOK) )
-                throw runtime_error ("Failed to construct SPatternsDialogWidgets");
-
-        gtk_combo_box_set_model_properly( eSFFDPatternList, mSFFDPatterns);
-        eSFFDPatternList_changed_cb_handler_id =
-                G_CONNECT_1 (eSFFDPatternList, changed);
-
-        // filter channels we don't have
-        for ( auto &H : SF.channels ) {
-                GtkTreeIter iter;
-                gtk_list_store_append(
-                        mSFFDChannels,
-                        &iter);
-                gtk_list_store_set(
-                        mSFFDChannels, &iter,
-                        0, H.name(),
-                        -1);
-        }
-        gtk_combo_box_set_model_properly( eSFFDChannel, mSFFDChannels);
-        eSFFDChannel_changed_cb_handler_id =
-                G_CONNECT_1 (eSFFDChannel, changed);
-
-        G_CONNECT_2 (wSFFD, configure, event);
-        G_CONNECT_1 (daSFFDThing, draw);
-        G_CONNECT_3 (daSFFDThing, button, press, event);
-        G_CONNECT_2 (daSFFDThing, scroll, event);
-        G_CONNECT_1 (daSFFDField, draw);
-        G_CONNECT_2 (daSFFDField, scroll, event);
-        G_CONNECT_3 (daSFFDField, motion, notify, event);
-        G_CONNECT_3 (daSFFDField, button, press, event);
-        G_CONNECT_1 (bSFFDProfileSave, clicked);
-        G_CONNECT_1 (bSFFDProfileDiscard, clicked);
-        G_CONNECT_1 (bSFFDProfileRevert, clicked);
-        G_CONNECT_1 (bSFFDSearch, clicked);
-        G_CONNECT_1 (bSFFDAgain, clicked);
-        G_CONNECT_1 (eSFFDPatternSaveName, changed);
-        G_CONNECT_1 (iSFFDFieldDrawMatchIndex, toggled);
-        G_CONNECT_1 (iSFFDMarkPhasicEventSpindles, activate);
-        G_CONNECT_1 (iSFFDMarkPhasicEventKComplexes, activate);
-        G_CONNECT_1 (iSFFDMarkPlain, activate);
-
-        for ( auto& W : {eSFFDEnvTightness,
-                         eSFFDBandPassFrom, eSFFDBandPassUpto, eSFFDBandPassOrder,
-                         eSFFDDZCDFStep, eSFFDDZCDFSigma, eSFFDDZCDFSmooth} )
-                g_signal_connect(
-                        W, "value-changed",
-                        (GCallback)eSFFD_any_pattern_value_changed_cb,
-                        this);
-        for ( auto& W : {eSFFDParameterA, eSFFDParameterB, eSFFDParameterC, eSFFDParameterD} ) {
-                g_signal_connect(
-                        W, "value-changed",
-                        (GCallback)eSFFD_any_criteria_value_changed_cb,
-                        this);
-                g_signal_connect(
-                        W, "focus-in-event",
-                        (GCallback)eSFFD_any_criteria_focus_in_event_cb,
-                        this);
-        }
-        for ( auto& W : {eSFFDPatternSaveOriginUser, eSFFDPatternSaveOriginExperiment, eSFFDPatternSaveOriginSubject} )
-                g_signal_connect(
-                        W, "toggled",
-                        (GCallback)eSFFD_any_pattern_origin_toggled_cb,
-                        this);
-        for ( auto& W : {iSFFDFieldProfileTypeRaw, iSFFDFieldProfileTypePSD, iSFFDFieldProfileTypeMC, iSFFDFieldProfileTypeSWU} )
-                g_signal_connect(
-                        W, "toggled",
-                        (GCallback)iSFFD_any_field_profile_type_toggled_cb,
-                        this);
-
-        G_CONNECT_1 (wSFFD, show);
-        G_CONNECT_1 (wSFFD, hide);
-}
-
-SPatternsDialogWidgets::
-~SPatternsDialogWidgets ()
-{
-        // destroy toplevels
-        gtk_widget_destroy( (GtkWidget*)wSFFD);
-        g_object_unref( (GObject*)mSFFDPatterns);
-        g_object_unref( (GObject*)mSFFDChannels);
-        g_object_unref( (GObject*)builder);
-}
-
-
-// Local Variables:
-// Mode: c++
-// indent-tabs-mode: nil
-// tab-width: 8
-// c-basic-offset: 8
-// End:
diff --git a/upstream/src/aghermann/ui/sf/d/patterns-draw.cc b/upstream/src/aghermann/ui/sf/d/patterns-draw.cc
index 74e8b58..5240aaf 100644
--- a/upstream/src/aghermann/ui/sf/d/patterns-draw.cc
+++ b/upstream/src/aghermann/ui/sf/d/patterns-draw.cc
@@ -48,7 +48,7 @@ void
 SScoringFacility::SPatternsDialog::
 draw_thing( cairo_t *cr)
 {
-        if ( current_pattern == patterns.end() ) {
+        if ( current_profile == profiles.end() ) {
                 cairo_put_banner( cr, da_thing_wd, da_thing_ht, "(make a selection)");
                 return;
         }
@@ -56,7 +56,7 @@ draw_thing( cairo_t *cr)
       // ticks
         cairo_select_font_face( cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
         cairo_set_font_size( cr, 9);
-        double  seconds = (double)current_pattern->thing.size() / current_pattern->samplerate;
+        double  seconds = (double)current_profile->thing.size() / current_profile->samplerate;
         for ( size_t i8 = 0; (float)i8 / 8 < seconds; ++i8 ) {
                 _p._p.CwB[SExpDesignUI::TColour::sf_ticks].set_source_rgba( cr);
                 cairo_set_line_width( cr, (i8%8 == 0) ? 1. : (i8%4 == 0) ? .6 : .3);
@@ -73,14 +73,14 @@ draw_thing( cairo_t *cr)
                 }
         }
 
-        size_t  run = current_pattern->pattern_size_essential();
+        size_t  run = current_profile->pattern_size_essential();
 
       // thing
         int     zeroline = da_thing_ht/2;
         cairo_set_source_rgb( cr, 0., 0., 0.);
         cairo_set_line_width( cr, .8);
         cairo_draw_signal(
-                cr, current_pattern->thing, 0, current_pattern->thing.size(),
+                cr, current_profile->thing, 0, current_profile->thing.size(),
                 da_thing_wd, 0, zeroline,
                 thing_display_scale);
         cairo_stroke( cr);
@@ -88,9 +88,9 @@ draw_thing( cairo_t *cr)
         // lines marking out context
         cairo_set_source_rgba( cr, 0.9, 0.9, 0.9, .5);
         cairo_set_line_width( cr, 1.);
-        cairo_rectangle( cr, 0., 0., (float)current_pattern->context.first / current_pattern->thing.size() * da_thing_wd, da_thing_ht);
-        cairo_rectangle( cr, (float)(current_pattern->context.first + run) / current_pattern->thing.size() * da_thing_wd, 0,
-                         (float)(current_pattern->context.second) / current_pattern->thing.size() * da_thing_wd, da_thing_ht);
+        cairo_rectangle( cr, 0., 0., (float)current_profile->context.first / current_profile->thing.size() * da_thing_wd, da_thing_ht);
+        cairo_rectangle( cr, (float)(current_profile->context.first + run) / current_profile->thing.size() * da_thing_wd, 0,
+                         (float)(current_profile->context.second) / current_profile->thing.size() * da_thing_wd, da_thing_ht);
         cairo_fill( cr);
         cairo_stroke( cr);
 
@@ -102,8 +102,8 @@ draw_thing( cairo_t *cr)
               // envelope
                 {
                         if ( 0 == sigproc::envelope(
-                                     {current_pattern->thing, current_pattern->samplerate}, Pp2.env_scope,
-                                     1./current_pattern->samplerate,
+                                     {current_profile->thing, current_profile->samplerate}, Pp.env_scope,
+                                     1./current_profile->samplerate,
                                      &env_l, &env_u) ) {
                                 cairo_put_banner( cr, da_thing_wd, da_thing_ht, "Pattern is too short for this envelope scope");
                                 goto out;
@@ -123,13 +123,13 @@ draw_thing( cairo_t *cr)
                 }
               // target frequency
                 {
-                        if ( Pp2.bwf_ffrom >= Pp2.bwf_fupto ) {
+                        if ( Pp.bwf_ffrom >= Pp.bwf_fupto ) {
                                 cairo_put_banner( cr, da_thing_wd, da_thing_ht, "Bad band-pass range");
                                 goto out;
                         }
                         target_freq = exstrom::band_pass(
-                                current_pattern->thing, current_pattern->samplerate,
-                                Pp2.bwf_ffrom, Pp2.bwf_fupto, Pp2.bwf_order, true);
+                                current_profile->thing, current_profile->samplerate,
+                                Pp.bwf_ffrom, Pp.bwf_fupto, Pp.bwf_order, true);
 
                         cairo_set_source_rgba( cr, 0.3, 0.3, 0.3, .5);
                         cairo_set_line_width( cr, 3.);
@@ -141,17 +141,17 @@ draw_thing( cairo_t *cr)
 
               // dzcdf
                 {
-                        if ( current_pattern->samplerate < 10 ) {
+                        if ( current_profile->samplerate < 10 ) {
                                 cairo_put_banner( cr, da_thing_wd, da_thing_ht, "Samplerate is too low");
                                 goto out;
                         }
-                        if ( Pp2.dzcdf_step * 10 > current_pattern->pattern_length() ) { // require at least 10 dzcdf points
+                        if ( Pp.dzcdf_step * 10 > current_profile->pattern_length() ) { // require at least 10 dzcdf points
                                 cairo_put_banner( cr, da_thing_wd, da_thing_ht, "Selection is too short for DZCDF");
                                 goto out;
                         }
 
-                        dzcdf = sigproc::dzcdf( sigproc::SSignalRef<TFloat> {current_pattern->thing, current_pattern->samplerate},
-                                                Pp2.dzcdf_step, Pp2.dzcdf_sigma, Pp2.dzcdf_smooth);
+                        dzcdf = sigproc::dzcdf( sigproc::SSignalRef<TFloat> {current_profile->thing, current_profile->samplerate},
+                                                Pp.dzcdf_step, Pp.dzcdf_sigma, Pp.dzcdf_smooth);
                         float   dzcdf_display_scale = da_thing_ht/4. / dzcdf.max();
 
                         cairo_set_source_rgba( cr, 0.3, 0.3, 0.99, .8);
@@ -231,7 +231,7 @@ draw_field( cairo_t *cr)
 #define KEKE(R,G,B,N)                                                        \
         {cairo_set_source_rgba( cr, R, G, B, .5);                        \
                 cairo_move_to( cr, 0, da_field_ht-5);                        \
-                size_t inc = max((int)(increment * current_pattern->samplerate), 1); \
+                size_t inc = max((int)(increment * current_profile->samplerate), 1); \
                 for ( size_t i = 0; i < diff_line.size(); i += inc )        \
                         cairo_line_to( cr, ((double)i)/diff_line.size() * da_field_wd, \
                                        da_field_ht - 5 - get<N>(criteria) / get<N>(diff_line[i]) * 20); \
diff --git a/upstream/src/aghermann/ui/sf/d/patterns-profiles.cc b/upstream/src/aghermann/ui/sf/d/patterns-profiles.cc
index 18fb7b9..fef0caf 100644
--- a/upstream/src/aghermann/ui/sf/d/patterns-profiles.cc
+++ b/upstream/src/aghermann/ui/sf/d/patterns-profiles.cc
@@ -20,21 +20,6 @@ using namespace std;
 using namespace agh::ui;
 
 
-list<agh::pattern::SPattern<TFloat>>::iterator
-SScoringFacility::SPatternsDialog::
-pattern_by_idx( size_t idx)
-{
-        size_t i = 0;
-        for ( auto I = patterns.begin(); I != patterns.end(); ++I )
-                if ( i == idx )
-                        return I;
-                else
-                        ++i;
-        throw invalid_argument ("Current pattern index invalid");
-}
-
-
-
 int
 SScoringFacility::SPatternsDialog::
 import_from_selection( SScoringFacility::SChannel& field)
@@ -59,8 +44,10 @@ import_from_selection( SScoringFacility::SChannel& field)
                      "Sure to proceed with search?") )
                 return -3;
 
+        gtk_widget_show( (GtkWidget*)wSFFD);
+
         size_t  context_before // agh::alg::ensure_within(
-                = (field.selection_start < current_pattern->context_pad)
+                = (field.selection_start < current_profile->context_pad)
                 ? pattern::SPattern<TFloat>::context_pad - field.selection_start
                 : pattern::SPattern<TFloat>::context_pad,
                 context_after
@@ -70,21 +57,23 @@ import_from_selection( SScoringFacility::SChannel& field)
                 full_sample = run + context_before + context_after;
 
         // transient is always the last
-        if ( patterns.empty() || patterns.back().level != TExpDirLevel::transient )
-                patterns.emplace_back(
+        if ( profiles.empty() || profiles.back().level != TExpDirLevel::transient )
+                profiles.emplace_back(
                         *_p._p.ED,
                         agh::SExpDirLevelId {_p._p.ED->group_of(_p.csubject()), _p.csubject().id, _p.session()});
         {
-                auto& P = patterns.back();
+                auto& P = profiles.back();
                 P.thing.resize( full_sample);
                 P.thing = field.signal_filtered[ slice (field.selection_start - context_before, full_sample, 1) ];
                 P.samplerate = field.samplerate();
                 P.context = {context_before, context_after};
-                P.Pp = Pp2;
+                P.Pp = Pp;
                 P.criteria = criteria;
+
+                Pp2 = P;
         }
 
-        current_pattern = prev(patterns.end());
+        current_profile = prev(profiles.end());
         populate_combo();
 
         field_channel_saved = field_channel = &field;
@@ -101,93 +90,6 @@ import_from_selection( SScoringFacility::SChannel& field)
         return 0;
 }
 
-
-
-
-void
-SScoringFacility::SPatternsDialog::
-load_patterns()
-{
-        patterns.clear();
-
-        using namespace agh;
-        for ( auto A : {TExpDirLevel::system, TExpDirLevel::user, TExpDirLevel::experiment, TExpDirLevel::subject} )
-                patterns.splice(
-                        patterns.end(),
-                        load_profiles_from_location<pattern::SPattern<TFloat>>(
-                                pattern::SPattern<TFloat>::common_subdir,
-                                A,
-                                *_p._p.ED,
-                                {_p._p.ED->group_of(_p.csubject()), _p.csubject().id, _p.session()}
-                                ));
-
-        current_pattern = patterns.end();
-}
-
-
-
-void
-SScoringFacility::SPatternsDialog::
-save_patterns()
-{
-        for ( auto& P : patterns )
-                P.save();
-}
-
-
-void
-SScoringFacility::SPatternsDialog::
-populate_combo()
-{
-        g_signal_handler_block( eSFFDPatternList, eSFFDPatternList_changed_cb_handler_id);
-        gtk_list_store_clear( mSFFDPatterns);
-
-        if ( not patterns.empty() ) {
-                GtkTreeIter iter, current_pattern_iter;
-                for ( auto I = patterns.begin(); I != patterns.end(); ++I ) {
-                        gtk_list_store_append(
-                                mSFFDPatterns,
-                                &iter);
-                        gtk_list_store_set(
-                                mSFFDPatterns, &iter,
-                                0, snprintf_buf( "%s %s", I->exp_dir_level_s(), I->name.c_str()),
-                                -1);
-                        if ( I == current_pattern )
-                                current_pattern_iter = iter;
-                }
-
-                gtk_combo_box_set_active_iter( eSFFDPatternList, &current_pattern_iter);
-        } else
-                gtk_combo_box_set_active_iter( eSFFDPatternList, NULL);
-
-        g_signal_handler_unblock( eSFFDPatternList, eSFFDPatternList_changed_cb_handler_id);
-}
-
-
-
-// void
-// SScoringFacility::SPatternsDialog::
-// save_patterns()
-// {
-//         for ( auto& P : patterns )
-//                 P.save();
-// }
-
-
-void
-SScoringFacility::SPatternsDialog::
-discard_current_pattern()
-{
-        if ( current_pattern == patterns.end() )
-                return;
-
-        auto todelete = current_pattern;
-        current_pattern = next(current_pattern);
-        todelete->delete_file();
-        patterns.erase( todelete);
-}
-
-
 // Local Variables:
 // Mode: c++
 // indent-tabs-mode: nil
diff --git a/upstream/src/aghermann/ui/sf/d/patterns-profiles_cb.cc b/upstream/src/aghermann/ui/sf/d/patterns-profiles_cb.cc
index e10a5dc..03e5b62 100644
--- a/upstream/src/aghermann/ui/sf/d/patterns-profiles_cb.cc
+++ b/upstream/src/aghermann/ui/sf/d/patterns-profiles_cb.cc
@@ -25,30 +25,22 @@ using namespace agh::ui;
 
 extern "C" {
 
+
 void
-eSFFDPatternList_changed_cb(
+eSFFDProfileList_changed_cb(
         GtkComboBox *combo,
         const gpointer userdata)
 {
         auto& FD = *(SScoringFacility::SPatternsDialog*)userdata;
 
-        if ( FD.current_pattern != FD.patterns.end() ) {
-                FD.current_pattern->Pp = FD.Pp2;
-                FD.current_pattern->criteria = FD.criteria;
-        }
-
-        gint ci = gtk_combo_box_get_active( combo);
-        if ( ci != -1 ) {
-                FD.current_pattern = FD.pattern_by_idx(ci);
-                FD.Pp2 = FD.current_pattern->Pp;
-                FD.criteria = FD.current_pattern->criteria;
-                FD.atomic_up();
+        FD.eXProfileList_changed_cb();
+
+        if ( FD.current_profile != FD.profiles.end() ) {
                 FD.thing_display_scale = FD.field_channel->signal_display_scale;
         } else
                 gtk_label_set_text( FD.lSFFDParametersBrief, "");
 
         FD.setup_controls_for_find();
-        FD.set_profile_manage_buttons_visibility();
 
         gtk_widget_queue_draw( (GtkWidget*)FD.daSFFDThing);
 }
@@ -62,89 +54,35 @@ bSFFDProfileSave_clicked_cb(
 {
         auto& FD = *(SScoringFacility::SPatternsDialog*)userdata;
 
-        g_signal_emit_by_name( FD.eSFFDPatternSaveName, "changed");
-
-        if ( GTK_RESPONSE_OK == gtk_dialog_run( FD.wSFFDPatternSave) ) {
-                using namespace agh;
-
-                // replace unnamed, else check if one exists, else add new
-                auto this_name = gtk_entry_get_text( FD.eSFFDPatternSaveName);
-                auto this_level =
-                        gtk_toggle_button_get_active( FD.eSFFDPatternSaveOriginSubject)
-                        ? TExpDirLevel::subject
-                        : gtk_toggle_button_get_active( FD.eSFFDPatternSaveOriginExperiment)
-                        ? TExpDirLevel::experiment
-                        : TExpDirLevel::user;
-
-                auto overwriting =
-                        find_if( FD.patterns.begin(), FD.patterns.end(),
-                                 [&] ( const pattern::SPattern<TFloat>& P) -> bool
-                                 { return P.name == this_name && P.level == this_level; });
-                auto& P =
-                        (overwriting != FD.patterns.end())
-                        ? *overwriting
-                        : (FD.current_pattern->level == agh::TExpDirLevel::transient)
-                        ? * FD.current_pattern
-                        : *(FD.current_pattern = FD.patterns.insert(FD.current_pattern, *FD.current_pattern));
-
-                tie(P.name, P.level, P.Pp, P.criteria) =
-                        make_tuple(
-                                this_name,
-                                this_level,
-                                FD.Pp2,
-                                FD.criteria);
-
-                FD.populate_combo();
-                FD.set_profile_manage_buttons_visibility();
-        }
+        FD.bXProfileSave_clicked_cb();
+
+        FD.setup_controls_for_find();
 }
 
 
-namespace {
 void
-hildebranden( const gpointer userdata)
-{
-        auto& FD = *(SScoringFacility::SPatternsDialog*)userdata;
-
-        gtk_widget_set_sensitive(
-                (GtkWidget*)FD.bSFFDPatternSaveOK,
-                gtk_entry_get_text_length( FD.eSFFDPatternSaveName) > 0);
-
-        using namespace agh;
-        auto this_name = gtk_entry_get_text( FD.eSFFDPatternSaveName);
-        auto this_level = gtk_toggle_button_get_active( FD.eSFFDPatternSaveOriginSubject)
-                        ? TExpDirLevel::subject
-                        : gtk_toggle_button_get_active( FD.eSFFDPatternSaveOriginExperiment)
-                        ? TExpDirLevel::experiment
-                        : TExpDirLevel::user;
-
-        bool overwriting =
-                find_if( FD.patterns.begin(), FD.patterns.end(),
-                         [&] ( const pattern::SPattern<TFloat>& P) -> bool
-                         { return P.name == this_name && P.level == this_level; })
-                != FD.patterns.end();
-        gtk_button_set_label(
-                FD.bSFFDPatternSaveOK,
-                overwriting ? "Overwrite" : "Save");
-}
-}
-
-void eSFFDPatternSaveName_changed_cb(
+eSFFDProfileSaveName_changed_cb(
         GtkEditable*,
         const gpointer userdata)
 {
-        hildebranden(userdata);
+        auto& FD = *(SScoringFacility::SPatternsDialog*)userdata;
+
+        FD.eXProfileSaveName_changed_cb();
 }
 
 void
-eSFFD_any_pattern_origin_toggled_cb(
+eSFFD_any_profile_origin_toggled_cb(
         GtkRadioButton*,
         const gpointer userdata)
 {
-        hildebranden(userdata);
+        auto& FD = *(SScoringFacility::SPatternsDialog*)userdata;
+
+        FD.eX_any_profile_origin_toggled_cb();
 }
 
 
+
+
 void
 bSFFDProfileDiscard_clicked_cb(
         GtkButton*,
@@ -152,23 +90,8 @@ bSFFDProfileDiscard_clicked_cb(
 {
         auto& FD = *(SScoringFacility::SPatternsDialog*)userdata;
 
-        gint ci = gtk_combo_box_get_active( FD.eSFFDPatternList);
-
-        assert ( FD.current_pattern != FD.patterns.end() );
-        assert ( ci != -1 );
-        assert ( ci < (int)FD.patterns.size() );
+        FD.bXProfileDiscard_clicked_cb();
 
-        FD.discard_current_pattern();
-
-        if ( not FD.patterns.empty() ) {
-                FD.Pp2 = FD.current_pattern->Pp;
-                FD.criteria = FD.current_pattern->criteria;
-
-                FD.atomic_up();
-        }
-
-        FD.populate_combo();
-        FD.set_profile_manage_buttons_visibility();
         FD.setup_controls_for_find();
 
         gtk_widget_queue_draw( (GtkWidget*)FD.daSFFDThing);
@@ -182,13 +105,9 @@ bSFFDProfileRevert_clicked_cb(
 {
         auto& FD = *(SScoringFacility::SPatternsDialog*)userdata;
 
-        assert ( FD.current_pattern != FD.patterns.end() );
-        assert ( FD.current_pattern->level != agh::TExpDirLevel::transient );
-
-        FD.Pp2 = FD.current_pattern->Pp;
-        FD.criteria = FD.current_pattern->criteria;
+        FD.bXProfileRevert_clicked_cb();
 
-        FD.atomic_up();
+        FD.setup_controls_for_find();
 
         FD.set_profile_manage_buttons_visibility();
 }
diff --git a/upstream/src/aghermann/ui/sf/d/patterns.cc b/upstream/src/aghermann/ui/sf/d/patterns.cc
index 88571d0..1f349c1 100644
--- a/upstream/src/aghermann/ui/sf/d/patterns.cc
+++ b/upstream/src/aghermann/ui/sf/d/patterns.cc
@@ -27,43 +27,182 @@ patterns_d()
 }
 
 SScoringFacility::SPatternsDialog::
-SPatternsDialog (SScoringFacility& parent)
-      : SPatternsDialogWidgets (parent),
+SPatternsDialog (SScoringFacility& p_)
+      : SDirlevelStorableAdapter<pattern::SPattern<TFloat>> (
+              *p_._p.ED, agh::SExpDirLevelId {p_._p.ED->group_of(p_.csubject()), p_.csubject().id, p_.session()},
+              mSFFDProfiles, eSFFDProfileList, eSFFDProfileList_changed_cb_handler_id,
+              bSFFDProfileSave, bSFFDProfileRevert, bSFFDProfileDiscard,
+              wSFFDProfileSave, eSFFDProfileSaveName,
+              eSFFDProfileSaveOriginSubject, eSFFDProfileSaveOriginExperiment, eSFFDProfileSaveOriginUser,
+              bSFFDProfileSaveOK),
+        Pp (Pp2.Pp), criteria (Pp2.criteria),
         increment (.03),
         field_profile_type (metrics::TType::mc),
         suppress_redraw (false),
         draw_details (true),
         draw_match_index (true),
-        _p (parent)
+        _p (p_)
 {
-        W_V.reg( eSFFDEnvTightness,  &Pp2.env_scope);
-        W_V.reg( eSFFDBandPassOrder, &Pp2.bwf_order);
-        W_V.reg( eSFFDBandPassFrom,  &Pp2.bwf_ffrom);
-        W_V.reg( eSFFDBandPassUpto,  &Pp2.bwf_fupto);
-        W_V.reg( eSFFDDZCDFStep,     &Pp2.dzcdf_step);
-        W_V.reg( eSFFDDZCDFSigma,    &Pp2.dzcdf_sigma);
-        W_V.reg( eSFFDDZCDFSmooth,   &Pp2.dzcdf_smooth);
-
-        W_V.reg( eSFFDParameterA,    &get<0>(criteria));
-        W_V.reg( eSFFDParameterB,    &get<1>(criteria));
-        W_V.reg( eSFFDParameterC,    &get<2>(criteria));
-        W_V.reg( eSFFDParameterD,    &get<3>(criteria));
+      // 1. widgets
+        builder = gtk_builder_new();
+        if ( !gtk_builder_add_from_resource( builder, "/org/gtk/aghermann/sf-patterns.glade", NULL) )
+                throw runtime_error( "Failed to load SF::patterns glade resource");
+        gtk_builder_connect_signals( builder, NULL);
+
+        mSFFDProfiles =
+                gtk_list_store_new( 1, G_TYPE_STRING);
+        mSFFDChannels =
+                gtk_list_store_new( 1, G_TYPE_STRING);
+
+        if ( !AGH_GBGETOBJ (GtkDialog,         wSFFD) ||
+             !AGH_GBGETOBJ (GtkDrawingArea,    daSFFDThing) ||
+             !AGH_GBGETOBJ (GtkScrolledWindow, swSFFDThing) ||
+             !AGH_GBGETOBJ (GtkDrawingArea,    daSFFDField) ||
+             !AGH_GBGETOBJ (GtkMenuBar,        iibSFFDMenu) ||
+             !AGH_GBGETOBJ (GtkMenu,           iiSFFDField) ||
+             !AGH_GBGETOBJ (GtkMenu,           iiSFFDFieldProfileTypes) ||
+             !AGH_GBGETOBJ (GtkCheckMenuItem,  iSFFDFieldDrawMatchIndex) ||
+             !AGH_GBGETOBJ (GtkRadioMenuItem,  iSFFDFieldProfileTypeRaw) ||
+             !AGH_GBGETOBJ (GtkRadioMenuItem,  iSFFDFieldProfileTypePSD) ||
+             !AGH_GBGETOBJ (GtkRadioMenuItem,  iSFFDFieldProfileTypeMC)  ||
+             !AGH_GBGETOBJ (GtkRadioMenuItem,  iSFFDFieldProfileTypeSWU) ||
+             !AGH_GBGETOBJ (GtkMenuItem,       iSFFDMarkPhasicEventSpindles) ||
+             !AGH_GBGETOBJ (GtkMenuItem,       iSFFDMarkPhasicEventKComplexes) ||
+             !AGH_GBGETOBJ (GtkMenuItem,       iSFFDMarkPlain) ||
+             !AGH_GBGETOBJ (GtkScrolledWindow, swSFFDField) ||
+             !AGH_GBGETOBJ (GtkTable,          cSFFDSearchButton) ||
+             !AGH_GBGETOBJ (GtkTable,          cSFFDAgainButton) ||
+             !AGH_GBGETOBJ (GtkBox,            cSFFDSearching) ||
+             !AGH_GBGETOBJ (GtkTable,          cSFFDParameters) ||
+             !AGH_GBGETOBJ (GtkTable,          cSFFDCriteria) ||
+             !AGH_GBGETOBJ (GtkButton,         bSFFDSearch) ||
+             !AGH_GBGETOBJ (GtkButton,         bSFFDAgain) ||
+             !AGH_GBGETOBJ (GtkButton,         bSFFDProfileSave) ||
+             !AGH_GBGETOBJ (GtkButton,         bSFFDProfileDiscard) ||
+             !AGH_GBGETOBJ (GtkButton,         bSFFDProfileRevert) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDEnvTightness) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDBandPassOrder) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDBandPassFrom) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDBandPassUpto) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDDZCDFStep) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDDZCDFSigma) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDDZCDFSmooth) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDParameterA) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDParameterB) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDParameterC) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDParameterD) ||
+             !AGH_GBGETOBJ (GtkSpinButton,     eSFFDIncrement) ||
+             !AGH_GBGETOBJ (GtkHBox,           cSFFDLabelBox) ||
+             !AGH_GBGETOBJ (GtkLabel,          lSFFDParametersBrief) ||
+             !AGH_GBGETOBJ (GtkLabel,          lSFFDFoundInfo) ||
+             !AGH_GBGETOBJ (GtkComboBox,       eSFFDProfileList) ||
+             !AGH_GBGETOBJ (GtkComboBox,       eSFFDChannel) ||
+             !AGH_GBGETOBJ (GtkDialog,         wSFFDProfileSave) ||
+             !AGH_GBGETOBJ (GtkEntry,          eSFFDProfileSaveName) ||
+             !AGH_GBGETOBJ (GtkToggleButton,   eSFFDProfileSaveOriginSubject) ||
+             !AGH_GBGETOBJ (GtkToggleButton,   eSFFDProfileSaveOriginExperiment) ||
+             !AGH_GBGETOBJ (GtkToggleButton,   eSFFDProfileSaveOriginUser) ||
+             !AGH_GBGETOBJ (GtkButton,         bSFFDProfileSaveOK) )
+                throw runtime_error ("Failed to construct SPatternsDialogWidgets");
+
+        gtk_combo_box_set_model_properly( eSFFDProfileList, mSFFDProfiles);
+        eSFFDProfileList_changed_cb_handler_id =
+                G_CONNECT_1 (eSFFDProfileList, changed);
+
+        // filter channels we don't have
+        for ( auto &H : _p.channels ) {
+                GtkTreeIter iter;
+                gtk_list_store_append(
+                        mSFFDChannels,
+                        &iter);
+                gtk_list_store_set(
+                        mSFFDChannels, &iter,
+                        0, H.name(),
+                        -1);
+        }
+        gtk_combo_box_set_model_properly( eSFFDChannel, mSFFDChannels);
+        eSFFDChannel_changed_cb_handler_id =
+                G_CONNECT_1 (eSFFDChannel, changed);
+
+        G_CONNECT_2 (wSFFD, configure, event);
+        G_CONNECT_1 (daSFFDThing, draw);
+        G_CONNECT_3 (daSFFDThing, button, press, event);
+        G_CONNECT_2 (daSFFDThing, scroll, event);
+        G_CONNECT_1 (daSFFDField, draw);
+        G_CONNECT_2 (daSFFDField, scroll, event);
+        G_CONNECT_3 (daSFFDField, motion, notify, event);
+        G_CONNECT_3 (daSFFDField, button, press, event);
+        G_CONNECT_1 (bSFFDProfileSave, clicked);
+        G_CONNECT_1 (bSFFDProfileDiscard, clicked);
+        G_CONNECT_1 (bSFFDProfileRevert, clicked);
+        G_CONNECT_1 (bSFFDSearch, clicked);
+        G_CONNECT_1 (bSFFDAgain, clicked);
+        G_CONNECT_1 (eSFFDProfileSaveName, changed);
+        G_CONNECT_1 (iSFFDFieldDrawMatchIndex, toggled);
+        G_CONNECT_1 (iSFFDMarkPhasicEventSpindles, activate);
+        G_CONNECT_1 (iSFFDMarkPhasicEventKComplexes, activate);
+        G_CONNECT_1 (iSFFDMarkPlain, activate);
+
+        for ( auto& W : {eSFFDEnvTightness,
+                         eSFFDBandPassFrom, eSFFDBandPassUpto, eSFFDBandPassOrder,
+                         eSFFDDZCDFStep, eSFFDDZCDFSigma, eSFFDDZCDFSmooth} )
+                g_signal_connect(
+                        W, "value-changed",
+                        (GCallback)eSFFD_any_profile_value_changed_cb,
+                        this);
+        for ( auto& W : {eSFFDParameterA, eSFFDParameterB, eSFFDParameterC, eSFFDParameterD} ) {
+                g_signal_connect(
+                        W, "value-changed",
+                        (GCallback)eSFFD_any_criteria_value_changed_cb,
+                        this);
+                g_signal_connect(
+                        W, "focus-in-event",
+                        (GCallback)eSFFD_any_criteria_focus_in_event_cb,
+                        this);
+        }
+        for ( auto& W : {eSFFDProfileSaveOriginUser, eSFFDProfileSaveOriginExperiment, eSFFDProfileSaveOriginSubject} )
+                g_signal_connect(
+                        W, "toggled",
+                        (GCallback)eSFFD_any_profile_origin_toggled_cb,
+                        this);
+        for ( auto& W : {iSFFDFieldProfileTypeRaw, iSFFDFieldProfileTypePSD, iSFFDFieldProfileTypeMC, iSFFDFieldProfileTypeSWU} )
+                g_signal_connect(
+                        W, "toggled",
+                        (GCallback)iSFFD_any_field_profile_type_toggled_cb,
+                        this);
+
+        G_CONNECT_1 (wSFFD, show);
+        G_CONNECT_1 (wSFFD, hide);
+
+      // 2. dialog
+        W_V.reg( eSFFDEnvTightness,  &Pp.env_scope);
+        W_V.reg( eSFFDBandPassOrder, &Pp.bwf_order);
+        W_V.reg( eSFFDBandPassFrom,  &Pp.bwf_ffrom);
+        W_V.reg( eSFFDBandPassUpto,  &Pp.bwf_fupto);
+        W_V.reg( eSFFDDZCDFStep,     &Pp.dzcdf_step);
+        W_V.reg( eSFFDDZCDFSigma,    &Pp.dzcdf_sigma);
+        W_V.reg( eSFFDDZCDFSmooth,   &Pp.dzcdf_smooth);
+
+        W_V.reg( eSFFDParameterA,    &get<0>(Pp2.criteria));
+        W_V.reg( eSFFDParameterB,    &get<1>(Pp2.criteria));
+        W_V.reg( eSFFDParameterC,    &get<2>(Pp2.criteria));
+        W_V.reg( eSFFDParameterD,    &get<3>(Pp2.criteria));
 
         W_V.reg( eSFFDIncrement,     &increment);
 
         atomic_up();
-
-        load_patterns();
 }
 
 SScoringFacility::SPatternsDialog::
 ~SPatternsDialog ()
 {
-        // save_patterns(); // saved by ~SPattern
-
-        // g_object_unref( mPatterns);
-        gtk_widget_destroy( (GtkWidget*)wSFFDPatternSave);
+        // save_profiles(); // saved by ~SPattern
+        // destroy toplevels
+        gtk_widget_destroy( (GtkWidget*)wSFFDProfileSave);
         gtk_widget_destroy( (GtkWidget*)wSFFD);
+        g_object_unref( (GObject*)mSFFDProfiles);
+        g_object_unref( (GObject*)mSFFDChannels);
+        g_object_unref( (GObject*)builder);
 }
 
 
@@ -75,22 +214,22 @@ void
 SScoringFacility::SPatternsDialog::
 search()
 {
-        assert (field_channel and current_pattern != patterns.end());
+        assert (field_channel and current_profile != profiles.end());
 
         if ( field_channel != field_channel_saved )
                 field_channel_saved = field_channel;
 
         pattern::CPatternTool<TFloat> cpattern
-                ({current_pattern->thing, current_pattern->samplerate},
-                 current_pattern->context,
-                 Pp2); // use this for the case when modiified current_pattern changes have not been committed
+                ({current_profile->thing, current_profile->samplerate},
+                 current_profile->context,
+                 Pp); // use this for the case when modiified current_profile changes have not been committed
         diff_line =
                 (cpattern.do_search(
-                        field_channel->signal_envelope( Pp2.env_scope).first,
-                        field_channel->signal_envelope( Pp2.env_scope).second,
-                        field_channel->signal_bandpass( Pp2.bwf_ffrom, Pp2.bwf_fupto, Pp2.bwf_order),
-                        field_channel->signal_dzcdf( Pp2.dzcdf_step, Pp2.dzcdf_sigma, Pp2.dzcdf_smooth),
-                        increment * current_pattern->samplerate),
+                        field_channel->signal_envelope( Pp.env_scope).first,
+                        field_channel->signal_envelope( Pp.env_scope).second,
+                        field_channel->signal_bandpass( Pp.bwf_ffrom, Pp.bwf_fupto, Pp.bwf_order),
+                        field_channel->signal_dzcdf( Pp.dzcdf_step, Pp.dzcdf_sigma, Pp.dzcdf_smooth),
+                        increment * current_profile->samplerate),
                  cpattern.diff);
 }
 
@@ -99,16 +238,16 @@ size_t
 SScoringFacility::SPatternsDialog::
 find_occurrences()
 {
-        if ( unlikely (current_pattern == patterns.end()) )
+        if ( unlikely (current_profile == profiles.end()) )
                 return 0;
 
         occurrences.resize(0);
-        size_t inc = max((int)(increment * current_pattern->samplerate), 1);
-        for ( size_t i = 0; i < diff_line.size() - current_pattern->thing.size(); i += inc )
+        size_t inc = max((int)(increment * current_profile->samplerate), 1);
+        for ( size_t i = 0; i < diff_line.size() - current_profile->thing.size(); i += inc )
                 if ( diff_line[i].good_enough( criteria) ) {
                         occurrences.push_back(i);
                         i +=  // avoid overlapping occurrences *and* ensure we hit the stride
-                                current_pattern->pattern_size_essential()/inc * inc;
+                                current_profile->pattern_size_essential()/inc * inc;
                 }
 
         restore_annotations();
@@ -127,8 +266,8 @@ occurrences_to_annotations( sigfile::SAnnotation::TType t)
                 sigfile::mark_annotation(
                         field_channel->annotations,
                         ((double)occurrences[o]) / field_channel->samplerate(),
-                        ((double)occurrences[o] + current_pattern->pattern_size_essential()) / field_channel->samplerate(),
-                        snprintf_buf("%s (%zu)", current_pattern->name.c_str(), o+1),
+                        ((double)occurrences[o] + current_profile->pattern_size_essential()) / field_channel->samplerate(),
+                        snprintf_buf("%s (%zu)", current_profile->name.c_str(), o+1),
                         t);
 }
 
@@ -154,7 +293,7 @@ void
 SScoringFacility::SPatternsDialog::
 setup_controls_for_find()
 {
-        bool    have_any = current_pattern != patterns.end();
+        bool    have_any = current_profile != profiles.end();
 
         gtk_widget_set_visible( (GtkWidget*)cSFFDSearchButton, have_any and TRUE);
         gtk_widget_set_visible( (GtkWidget*)cSFFDSearching, FALSE);
@@ -165,7 +304,7 @@ setup_controls_for_find()
         gtk_widget_set_visible( (GtkWidget*)swSFFDField, FALSE);
         gtk_widget_set_visible( (GtkWidget*)cSFFDCriteria, FALSE);
 
-        gtk_widget_set_sensitive( (GtkWidget*)eSFFDPatternList, TRUE);
+        gtk_widget_set_sensitive( (GtkWidget*)eSFFDProfileList, TRUE);
 
         gtk_widget_set_visible( (GtkWidget*)iibSFFDMenu, FALSE);
 
@@ -185,7 +324,7 @@ setup_controls_for_wait()
         gtk_widget_set_visible( (GtkWidget*)swSFFDField, FALSE);
         gtk_widget_set_visible( (GtkWidget*)cSFFDCriteria, FALSE);
 
-        gtk_widget_set_sensitive( (GtkWidget*)eSFFDPatternList, FALSE);
+        gtk_widget_set_sensitive( (GtkWidget*)eSFFDProfileList, FALSE);
 
         gtk_widget_set_visible( (GtkWidget*)iibSFFDMenu, FALSE);
 }
@@ -203,26 +342,13 @@ setup_controls_for_tune()
         gtk_widget_set_visible( (GtkWidget*)swSFFDField, TRUE);
         gtk_widget_set_visible( (GtkWidget*)cSFFDCriteria, TRUE);
 
-        gtk_widget_set_sensitive( (GtkWidget*)eSFFDPatternList, FALSE);
+        gtk_widget_set_sensitive( (GtkWidget*)eSFFDProfileList, FALSE);
 
         gtk_widget_set_visible( (GtkWidget*)iibSFFDMenu, TRUE);
 }
 
 
 
-void
-SScoringFacility::SPatternsDialog::
-set_profile_manage_buttons_visibility()
-{
-        bool    have_active  = current_pattern != patterns.end(),
-                is_transient = have_active && current_pattern->level == agh::TExpDirLevel::transient,
-                is_modified  = have_active && not (current_pattern->Pp == Pp2); // and not (current_pattern->criteria == criteria);
-        gtk_widget_set_visible( (GtkWidget*)bSFFDProfileSave, have_active);
-        gtk_widget_set_visible( (GtkWidget*)bSFFDProfileRevert, have_active and not is_transient and is_modified);
-        gtk_widget_set_visible( (GtkWidget*)bSFFDProfileDiscard, have_active and not is_transient);
-        gtk_widget_set_sensitive( (GtkWidget*)eSFFDPatternList, not is_modified);
-}
-
 
 void
 SScoringFacility::SPatternsDialog::
diff --git a/upstream/src/aghermann/ui/sf/d/patterns.hh b/upstream/src/aghermann/ui/sf/d/patterns.hh
index ca42f08..529873a 100644
--- a/upstream/src/aghermann/ui/sf/d/patterns.hh
+++ b/upstream/src/aghermann/ui/sf/d/patterns.hh
@@ -13,7 +13,8 @@
 #define AGH_AGHERMANN_UI_SF_D_PATTERNS_H_
 
 #include "aghermann/patterns/patterns.hh"
-#include "aghermann/ui/sf/sf.hh"
+#include "aghermann/ui/dirlevel-storable-adapter.hh"
+//#include "aghermann/ui/sf/sf.hh"
 
 #if HAVE_CONFIG_H && !defined(VERSION)
 #  include "config.h"
@@ -25,80 +26,8 @@ namespace agh {
 namespace ui {
 
 
-struct SPatternsDialogWidgets {
-
-        explicit SPatternsDialogWidgets (SScoringFacility&); // need access to mAllChannels
-       ~SPatternsDialogWidgets ();
-
-        GtkBuilder
-                *builder;
-
-        GtkListStore
-                *mSFFDPatterns,
-                *mSFFDChannels;
-        GtkDialog
-                *wSFFD;
-        GtkComboBox
-                *eSFFDChannel,
-                *eSFFDPatternList;
-        GtkScrolledWindow
-                *swSFFDThing,
-                *swSFFDField;
-        GtkTable
-                *cSFFDParameters,
-                *cSFFDCriteria,
-                *cSFFDSearchButton,
-                *cSFFDAgainButton;
-        GtkBox        *cSFFDSearching;
-        GtkDrawingArea
-                *daSFFDThing,
-                *daSFFDField;
-        GtkMenuBar
-                *iibSFFDMenu;
-        GtkMenu        *iiSFFDField,
-                *iiSFFDFieldProfileTypes;
-        GtkCheckMenuItem
-                *iSFFDFieldDrawMatchIndex;
-        GtkMenuItem
-                *iSFFDMarkPhasicEventSpindles,
-                *iSFFDMarkPhasicEventKComplexes,
-                *iSFFDMarkPlain;
-        GtkRadioMenuItem
-                *iSFFDFieldProfileTypeRaw,
-                *iSFFDFieldProfileTypePSD,
-                *iSFFDFieldProfileTypeMC,
-                *iSFFDFieldProfileTypeSWU;
-        GtkButton
-                *bSFFDSearch, *bSFFDAgain,
-                *bSFFDProfileSave, *bSFFDProfileDiscard, *bSFFDProfileRevert;
-        GtkSpinButton
-                *eSFFDEnvTightness,
-                *eSFFDBandPassFrom, *eSFFDBandPassUpto, *eSFFDBandPassOrder,
-                *eSFFDDZCDFStep, *eSFFDDZCDFSigma, *eSFFDDZCDFSmooth,
-                *eSFFDParameterA, *eSFFDParameterB,
-                *eSFFDParameterC, *eSFFDParameterD,
-                *eSFFDIncrement;
-        GtkHBox *cSFFDLabelBox;
-        GtkLabel
-                *lSFFDParametersBrief,
-                *lSFFDFoundInfo;
-        GtkDialog
-                *wSFFDPatternSave;
-        GtkEntry
-                *eSFFDPatternSaveName;
-        GtkToggleButton
-                *eSFFDPatternSaveOriginSubject,
-                *eSFFDPatternSaveOriginExperiment,
-                *eSFFDPatternSaveOriginUser;
-        GtkButton
-                *bSFFDPatternSaveOK;
-        gulong  eSFFDChannel_changed_cb_handler_id,
-                eSFFDPatternList_changed_cb_handler_id;
-};
-
-
 struct SScoringFacility::SPatternsDialog
-  : public SPatternsDialogWidgets{
+  : public SDirlevelStorableAdapter<pattern::SPattern<TFloat>> {
 
         DELETE_DEFAULT_METHODS (SPatternsDialog);
 
@@ -106,28 +35,16 @@ struct SScoringFacility::SPatternsDialog
         explicit SPatternsDialog (SScoringFacility& parent);
        ~SPatternsDialog ();
 
-      // saved patterns
-        list<pattern::SPattern<TFloat>>
-                patterns;
-        list<pattern::SPattern<TFloat>>::iterator
-                current_pattern;
-        list<pattern::SPattern<TFloat>>::iterator
-        pattern_by_idx( size_t);
-
         int import_from_selection( SScoringFacility::SChannel&);
-        void load_patterns();
-        void save_patterns();
-        void discard_current_pattern();
-        void populate_combo();
-
-      // finding tool
-          pattern::SPatternPPack<TFloat>
-                Pp2;
+
+      // a copy of SPattern connected to widgets
+        pattern::SPatternPPack<TFloat>
+                &Pp;
+        pattern::CMatch
+                &criteria;
         double  increment; // in seconds
 
       // matches
-        pattern::CMatch
-                criteria;
         vector<pattern::CMatch>
                 diff_line;
         vector<size_t>
@@ -153,8 +70,7 @@ struct SScoringFacility::SPatternsDialog
         void update_field_check_menu_items();
 
       // draw
-        bool    suppress_w_v:1,
-                suppress_redraw:1,
+        bool    suppress_redraw:1,
                 draw_details:1,
                 draw_match_index:1;
         void draw_thing( cairo_t*);
@@ -163,21 +79,11 @@ struct SScoringFacility::SPatternsDialog
                 field_display_scale;
 
       // widgets
-        SUIVarCollection
-                W_V;
-        void atomic_up()
-                {
-                        suppress_w_v = true;
-                        W_V.up();
-                        suppress_w_v = false;
-                }
-
         void preselect_channel( int) const;
 
         void setup_controls_for_find();
         void setup_controls_for_wait();
         void setup_controls_for_tune();
-        void set_profile_manage_buttons_visibility();
 
         static const int
                 da_thing_ht = 200,
@@ -189,6 +95,72 @@ struct SScoringFacility::SPatternsDialog
 
         agh::ui::SScoringFacility&
                 _p;
+
+      // widgets
+        GtkBuilder
+                *builder;
+
+        GtkListStore
+                *mSFFDProfiles,
+                *mSFFDChannels;
+        GtkDialog
+                *wSFFD;
+        GtkComboBox
+                *eSFFDChannel,
+                *eSFFDProfileList;
+        GtkScrolledWindow
+                *swSFFDThing,
+                *swSFFDField;
+        GtkTable
+                *cSFFDParameters,
+                *cSFFDCriteria,
+                *cSFFDSearchButton,
+                *cSFFDAgainButton;
+        GtkBox  *cSFFDSearching;
+        GtkDrawingArea
+                *daSFFDThing,
+                *daSFFDField;
+        GtkMenuBar
+                *iibSFFDMenu;
+        GtkMenu *iiSFFDField,
+                *iiSFFDFieldProfileTypes;
+        GtkCheckMenuItem
+                *iSFFDFieldDrawMatchIndex;
+        GtkMenuItem
+                *iSFFDMarkPhasicEventSpindles,
+                *iSFFDMarkPhasicEventKComplexes,
+                *iSFFDMarkPlain;
+        GtkRadioMenuItem
+                *iSFFDFieldProfileTypeRaw,
+                *iSFFDFieldProfileTypePSD,
+                *iSFFDFieldProfileTypeMC,
+                *iSFFDFieldProfileTypeSWU;
+        GtkButton
+                *bSFFDSearch, *bSFFDAgain,
+                *bSFFDProfileSave, *bSFFDProfileRevert, *bSFFDProfileDiscard;
+        GtkSpinButton
+                *eSFFDEnvTightness,
+                *eSFFDBandPassFrom, *eSFFDBandPassUpto, *eSFFDBandPassOrder,
+                *eSFFDDZCDFStep, *eSFFDDZCDFSigma, *eSFFDDZCDFSmooth,
+                *eSFFDParameterA, *eSFFDParameterB,
+                *eSFFDParameterC, *eSFFDParameterD,
+                *eSFFDIncrement;
+        GtkHBox *cSFFDLabelBox;
+        GtkLabel
+                *lSFFDParametersBrief,
+                *lSFFDFoundInfo;
+        GtkDialog
+                *wSFFDProfileSave;
+        GtkEntry
+                *eSFFDProfileSaveName;
+        GtkToggleButton
+                *eSFFDProfileSaveOriginSubject,
+                *eSFFDProfileSaveOriginExperiment,
+                *eSFFDProfileSaveOriginUser;
+        GtkButton
+                *bSFFDProfileSaveOK;
+        gulong  eSFFDChannel_changed_cb_handler_id,
+                eSFFDProfileList_changed_cb_handler_id;
 };
 
 
@@ -196,7 +168,13 @@ struct SScoringFacility::SPatternsDialog
 } // namespace agh::ui
 
 extern "C" {
-void eSFFDPatternList_changed_cb( GtkComboBox*, gpointer);
+void eSFFDProfileList_changed_cb( GtkComboBox*, gpointer);
+void bSFFDProfileSave_clicked_cb( GtkButton*, gpointer);
+void bSFFDProfileDiscard_clicked_cb( GtkButton*, gpointer);
+void bSFFDProfileRevert_clicked_cb( GtkButton*, gpointer);
+
+void wSFFD_show_cb( GtkWidget*, gpointer);
+void wSFFD_hide_cb( GtkWidget*, gpointer);
 void eSFFDChannel_changed_cb( GtkComboBox*, gpointer);
 gboolean daSFFDField_draw_cb( GtkWidget*, cairo_t*, gpointer);
 gboolean daSFFDField_scroll_event_cb( GtkWidget*, GdkEventScroll*, gpointer);
@@ -207,26 +185,22 @@ gboolean daSFFDThing_button_press_event_cb( GtkWidget*, GdkEventButton*, gpointe
 gboolean daSFFDThing_scroll_event_cb( GtkWidget*, GdkEventScroll*, gpointer);
 void bSFFDSearch_clicked_cb( GtkButton*, gpointer);
 void bSFFDAgain_clicked_cb( GtkButton*, gpointer);
-void bSFFDProfileSave_clicked_cb( GtkButton*, gpointer);
-void bSFFDProfileDiscard_clicked_cb( GtkButton*, gpointer);
-void bSFFDProfileRevert_clicked_cb( GtkButton*, gpointer);
+
 gboolean eSFFD_any_criteria_focus_in_event_cb(GtkWidget*, GdkEvent*, gpointer);
-void wSFFD_show_cb( GtkWidget*, gpointer);
-void wSFFD_hide_cb( GtkWidget*, gpointer);
 gboolean wSFFD_configure_event_cb( GtkWidget*, GdkEventConfigure*, gpointer);
 void iSFFDFieldDrawMatchIndex_toggled_cb( GtkCheckMenuItem*, gpointer);
 void iSFFDMarkPhasicEventSpindles_activate_cb( GtkMenuItem*, gpointer);
 void iSFFDMarkPhasicEventKComplexes_activate_cb( GtkMenuItem*, gpointer);
 void iSFFDMarkPlain_activate_cb( GtkMenuItem*, gpointer);
-void eSFFDPatternSaveName_changed_cb(GtkEditable*, gpointer);
+void eSFFDProfileSaveName_changed_cb(GtkEditable*, gpointer);
 
-void eSFFD_any_pattern_origin_toggled_cb(GtkRadioButton*, gpointer);
-void eSFFD_any_pattern_value_changed_cb( GtkSpinButton*, gpointer);
+void eSFFD_any_profile_origin_toggled_cb(GtkRadioButton*, gpointer);
+void eSFFD_any_profile_value_changed_cb( GtkSpinButton*, gpointer);
 void eSFFD_any_criteria_value_changed_cb( GtkSpinButton*, gpointer);
 void iSFFD_any_field_profile_type_toggled_cb( GtkRadioMenuItem*, gpointer);
 }
 
-#endif // AGH_AGHERMANN_UI_SF_D_PATTERNS_H_
+#endif
 
 // Local Variables:
 // Mode: c++
diff --git a/upstream/src/aghermann/ui/sf/d/patterns_cb.cc b/upstream/src/aghermann/ui/sf/d/patterns_cb.cc
index 7c382a9..4727a50 100644
--- a/upstream/src/aghermann/ui/sf/d/patterns_cb.cc
+++ b/upstream/src/aghermann/ui/sf/d/patterns_cb.cc
@@ -268,9 +268,9 @@ bSFFDSearch_clicked_cb(
                         "A: <b>%g</b>  "
                         "B: <b>%g</b>/<b>%g</b>/<b>%d</b>  "
                         "C: <b>%g</b>/<b>%g</b>/<b>%d</b>",
-                        FD.Pp2.env_scope,
-                        FD.Pp2.bwf_ffrom, FD.Pp2.bwf_fupto, FD.Pp2.bwf_order,
-                        FD.Pp2.dzcdf_step, FD.Pp2.dzcdf_sigma, FD.Pp2.dzcdf_smooth));
+                        FD.Pp.env_scope,
+                        FD.Pp.bwf_ffrom, FD.Pp.bwf_fupto, FD.Pp.bwf_order,
+                        FD.Pp.dzcdf_step, FD.Pp.dzcdf_sigma, FD.Pp.dzcdf_smooth));
 
         gtk_widget_queue_draw( (GtkWidget*)FD.daSFFDField);
 
@@ -346,7 +346,7 @@ iSFFDMarkPlain_activate_cb(
 
 
 void
-eSFFD_any_pattern_value_changed_cb(
+eSFFD_any_profile_value_changed_cb(
         GtkSpinButton*,
         const gpointer userdata)
 {
@@ -460,7 +460,7 @@ wSFFD_show_cb(
         auto& FD = *(SScoringFacility::SPatternsDialog*)userdata;
 
         // new patterns may have appeared created by other SF instances, so
-        FD.load_patterns();
+        FD.load_profiles();
 
         FD.setup_controls_for_find();
         FD.populate_combo();
@@ -496,7 +496,7 @@ wSFFD_hide_cb(
                 }
         }
 
-        FD.save_patterns();
+        FD.save_profiles();
 }
 
 
diff --git a/upstream/src/aghermann/ui/sf/d/phasediff-construct.cc b/upstream/src/aghermann/ui/sf/d/phasediff-construct.cc
index 51e23a1..16709fc 100644
--- a/upstream/src/aghermann/ui/sf/d/phasediff-construct.cc
+++ b/upstream/src/aghermann/ui/sf/d/phasediff-construct.cc
@@ -76,8 +76,8 @@ SPhasediffDialogWidgets::
 ~SPhasediffDialogWidgets ()
 {
         gtk_widget_destroy( (GtkWidget*)wSFPD);
-        g_object_unref( (GObject*)builder);
         g_object_unref( (GObject*)mSFPDChannels);
+        g_object_unref( (GObject*)builder);
 }
 
 
diff --git a/upstream/src/aghermann/ui/sf/d/rk1968-construct.cc b/upstream/src/aghermann/ui/sf/d/rk1968-construct.cc
deleted file mode 100644
index f206b8d..0000000
--- a/upstream/src/aghermann/ui/sf/d/rk1968-construct.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- *       File name:  aghermann/ui/sf/d/rk1968-construct.cc
- *         Project:  Aghermann
- *          Author:  Andrei Zavada <johnhommer at gmail.com>
- * Initial version:  2013-09-07
- *
- *         Purpose:  scoring facility RK1968 dialog construct
- *
- *         License:  GPL
- */
-
-#include <stdexcept>
-
-#include "aghermann/ui/ui.hh"
-
-#include "rk1968.hh"
-
-using namespace std;
-using namespace agh::ui;
-
-SRK1968DialogWidgets::
-SRK1968DialogWidgets ()
-{
-        builder = gtk_builder_new();
-        if ( !gtk_builder_add_from_resource( builder, "/org/gtk/aghermann/sf-rk1968.glade", NULL) )
-                throw runtime_error( "Failed to load SF::rk1968 glade resource");
-        gtk_builder_connect_signals( builder, NULL);
-
-        if ( !AGH_GBGETOBJ (GtkDialog,     wSFRK) ||
-             !AGH_GBGETOBJ (GtkButton,     bSFRKProfileRevert) ||
-             !AGH_GBGETOBJ (GtkButton,     bSFRKProfileSave) ||
-             !AGH_GBGETOBJ (GtkButton,     bSFRKProfileDiscard) ||
-             !AGH_GBGETOBJ (GtkComboBox,   eSFRKProfileList) ||
-
-             !AGH_GBGETOBJ (GtkSpinButton, eSFRKNremThetaDeltaRatio) ||
-
-             !AGH_GBGETOBJ (GtkButton,     bSFRKRun) ||
-             !AGH_GBGETOBJ (GtkButton,     bSFRKModify) ||
-             !AGH_GBGETOBJ (GtkLabel,      lSFRKWorking) )
-                throw runtime_error ("Failed to construct SRK1968DialogWidgets");
-
-        mSFRKProfiles =
-                gtk_list_store_new( 1, G_TYPE_STRING);
-
-        gtk_combo_box_set_model_properly( eSFRKProfileList, mSFRKProfiles);
-        eSFRKProfileList_changed_cb_handler_id =
-                G_CONNECT_1 (eSFRKProfileList, changed);
-
-        
-}
-
-
-SRK1968DialogWidgets::
-~SRK1968DialogWidgets ()
-{
-        gtk_widget_destroy( (GtkWidget*)wSFRK);
-        g_object_unref( (GObject*)builder);
-}
-
-
-// Local Variables:
-// indent-tabs-mode: nil
-// tab-width: 8
-// c-basic-offset: 8
-// End:
diff --git a/upstream/src/aghermann/ui/sf/d/rk1968-profiles.cc b/upstream/src/aghermann/ui/sf/d/rk1968-profiles.cc
index 1ac9e11..e3a8e28 100644
--- a/upstream/src/aghermann/ui/sf/d/rk1968-profiles.cc
+++ b/upstream/src/aghermann/ui/sf/d/rk1968-profiles.cc
@@ -9,115 +9,17 @@
  *         License:  GPL
  */
 
-#include <tuple>
-
-#include "aghermann/ui/misc.hh"
-#include "aghermann/ui/sf/channel.hh"
+// #include "aghermann/expdesign/dirlevel.hh"
+// #include "aghermann/expdesign/expdesign.hh"
+// #include "aghermann/ui/misc.hh"
+// #include "aghermann/ui/mw/mw.hh"
+// #include "aghermann/ui/sf/channel.hh"
 #include "rk1968.hh"
 
 using namespace std;
 using namespace agh::ui;
 
 
-
-
-
-list<agh::rk1968::CScoreAssistant>::iterator
-SScoringFacility::SRK1968Dialog::
-profile_by_idx( size_t idx)
-{
-        size_t i = 0;
-        for ( auto I = profiles.begin(); I != profiles.end(); ++I )
-                if ( i == idx )
-                        return I;
-                else
-                        ++i;
-        throw invalid_argument ("Current profile index invalid");
-}
-
-
-
-
-void
-SScoringFacility::SRK1968Dialog::
-load_profiles()
-{
-        profiles.clear();
-
-        // profiles.splice(
-        //         profiles.end(), agh::rk1968::load_profile_from_location(
-        //                 make_system_profiles_location(),
-        //                 pattern::TOrigin::system));
-        
-        // patterns.splice(
-        //         patterns.end(), pattern::load_patterns_from_location<TFloat>(
-        //                 make_user_patterns_location(),
-        //                 pattern::TOrigin::user));
-        // patterns.splice(
-        //         patterns.end(), pattern::load_patterns_from_location<TFloat>(
-        //                 make_experiment_patterns_location( *_p._p.ED),
-        //                 pattern::TOrigin::experiment));
-        // patterns.splice(
-        //         patterns.end(), pattern::load_patterns_from_location<TFloat>(
-        //                 make_subject_patterns_location( *_p._p.ED, _p.csubject()),
-        //                 pattern::TOrigin::subject));
-
-        current_profile = profiles.end();
-}
-
-
-void
-SScoringFacility::SRK1968Dialog::
-populate_combo()
-{
-        g_signal_handler_block( eSFRKProfileList, eSFRKProfileList_changed_cb_handler_id);
-        gtk_list_store_clear( mSFRKProfiles);
-
-        if ( not profiles.empty() ) {
-                GtkTreeIter iter, current_profile_iter;
-                for ( auto I = profiles.begin(); I != profiles.end(); ++I ) {
-                        gtk_list_store_append(
-                                mSFRKProfiles, &iter);
-                        gtk_list_store_set(
-                                mSFRKProfiles, &iter,
-                                0, snprintf_buf( "%s %s", agh::exp_dir_level_s(I->level), I->name.c_str()),
-                                -1);
-                        if ( I == current_profile )
-                                current_profile_iter = iter;
-                }
-
-                gtk_combo_box_set_active_iter( eSFRKProfileList, &current_profile_iter);
-        } else
-                gtk_combo_box_set_active_iter( eSFRKProfileList, NULL);
-
-        g_signal_handler_unblock( eSFRKProfileList, eSFRKProfileList_changed_cb_handler_id);
-}
-
-
-
-void
-SScoringFacility::SRK1968Dialog::
-save_profiles()
-{
-        for ( auto& P : profiles )
-                P.save();
-}
-
-
-void
-SScoringFacility::SRK1968Dialog::
-discard_current_profile()
-{
-        if ( current_profile == profiles.end() )
-                return;
-
-        auto todelete = current_profile;
-        current_profile = next(current_profile);
-        todelete->delete_file();
-        profiles.erase( todelete);
-}
-
-
 // Local Variables:
 // Mode: c++
 // indent-tabs-mode: nil
diff --git a/upstream/src/aghermann/ui/sf/d/rk1968-profiles_cb.cc b/upstream/src/aghermann/ui/sf/d/rk1968-profiles_cb.cc
new file mode 100644
index 0000000..f2eedf3
--- /dev/null
+++ b/upstream/src/aghermann/ui/sf/d/rk1968-profiles_cb.cc
@@ -0,0 +1,93 @@
+/*
+ *       File name:  aghermann/ui/sf/d/rk1968-profiles_cb.cc
+ *         Project:  Aghermann
+ *          Author:  Andrei Zavada <johnhommer at gmail.com>
+ * Initial version:  2013-09-15
+ *
+ *         Purpose:  scoring facility: RK1968 dialog callbacks
+ *
+ *         License:  GPL
+ */
+
+#include "rk1968.hh"
+#include <cassert>
+
+using namespace std;
+using namespace agh::ui;
+
+extern "C" {
+
+void eSFRKProfileList_changed_cb(
+        GtkComboBox*,
+        gpointer userdata)
+{
+        auto& RK = *(SScoringFacility::SRK1968Dialog*)userdata;
+
+        RK.eXProfileList_changed_cb();
+}
+
+
+
+
+void
+bSFRKProfileSave_clicked_cb(
+        GtkButton*,
+        const gpointer userdata)
+{
+        auto& RK = *(SScoringFacility::SRK1968Dialog*)userdata;
+
+        RK.bXProfileSave_clicked_cb();
+}
+
+
+void
+bSFRKProfileDiscard_clicked_cb(
+        GtkButton*,
+        const gpointer userdata)
+{
+        auto& RK = *(SScoringFacility::SRK1968Dialog*)userdata;
+
+        RK.bXProfileDiscard_clicked_cb();
+}
+
+
+void
+bSFRKProfileRevert_clicked_cb(
+        GtkButton*,
+        const gpointer userdata)
+{
+        auto& RK = *(SScoringFacility::SRK1968Dialog*)userdata;
+
+        RK.bXProfileRevert_clicked_cb();
+}
+
+
+
+void eSFRKProfileSaveName_changed_cb(
+        GtkEditable*,
+        const gpointer userdata)
+{
+        auto& RK = *(SScoringFacility::SRK1968Dialog*)userdata;
+
+        RK.eXProfileSaveName_changed_cb();
+}
+
+void
+eSFRK_any_pattern_origin_toggled_cb(
+        GtkRadioButton*,
+        const gpointer userdata)
+{
+        auto& RK = *(SScoringFacility::SRK1968Dialog*)userdata;
+
+        RK.eXProfileSaveName_changed_cb();
+}
+
+
+
+} // extern "C"
+
+// Local Variables:
+// indent-tabs-mode: nil
+// tab-width: 8
+// c-basic-offset: 8
+// End:
diff --git a/upstream/src/aghermann/ui/sf/d/rk1968.cc b/upstream/src/aghermann/ui/sf/d/rk1968.cc
index 384e496..3602ccb 100644
--- a/upstream/src/aghermann/ui/sf/d/rk1968.cc
+++ b/upstream/src/aghermann/ui/sf/d/rk1968.cc
@@ -26,13 +26,71 @@ rk1968_d()
 
 SScoringFacility::SRK1968Dialog::
 SRK1968Dialog (SScoringFacility& p_)
-      : _p (p_)
+      : SDirlevelStorableAdapter<agh::rk1968::CScoreAssistant>(
+              *p_._p.ED, agh::SExpDirLevelId {p_._p.ED->group_of(p_.csubject()), p_.csubject().id, p_.session()},
+              mSFRKProfiles, eSFRKProfileList, eSFRKProfileList_changed_cb_handler_id,
+              bSFRKProfileSave, bSFRKProfileRevert, bSFRKProfileDiscard,
+              wSFRKProfileSave, eSFRKProfileSaveName,
+              eSFRKProfileSaveOriginSubject, eSFRKProfileSaveOriginExperiment, eSFRKProfileSaveOriginUser,
+              bSFRKProfileSaveOK),
+        _p (p_)
 {
-        //W_V.reg( eSFRKNremThetaDeltaRatio,        &A.nrem3_delta_theta_ratio);
+      // 1. widgets
+        builder = gtk_builder_new();
+        if ( !gtk_builder_add_from_resource( builder, "/org/gtk/aghermann/sf-rk1968.glade", NULL) )
+                throw runtime_error( "Failed to load SF::rk1968 glade resource");
+        gtk_builder_connect_signals( builder, NULL);
 
-        load_profiles();
+        if ( !AGH_GBGETOBJ (GtkDialog,     wSFRK) ||
+             !AGH_GBGETOBJ (GtkButton,     bSFRKProfileRevert) ||
+             !AGH_GBGETOBJ (GtkButton,     bSFRKProfileSave) ||
+             !AGH_GBGETOBJ (GtkButton,     bSFRKProfileDiscard) ||
+             !AGH_GBGETOBJ (GtkComboBox,   eSFRKProfileList) ||
+
+             !AGH_GBGETOBJ (GtkSpinButton, eSFRKNremThetaDeltaRatio) ||
+
+             !AGH_GBGETOBJ (GtkButton,     bSFRKTry) ||
+             !AGH_GBGETOBJ (GtkButton,     bSFRKModify) ||
+             !AGH_GBGETOBJ (GtkLabel,      lSFRKWorking) ||
+             !AGH_GBGETOBJ (GtkDialog,         wSFRKProfileSave) ||
+             !AGH_GBGETOBJ (GtkEntry,          eSFRKProfileSaveName) ||
+             !AGH_GBGETOBJ (GtkToggleButton,   eSFRKProfileSaveOriginSubject) ||
+             !AGH_GBGETOBJ (GtkToggleButton,   eSFRKProfileSaveOriginExperiment) ||
+             !AGH_GBGETOBJ (GtkToggleButton,   eSFRKProfileSaveOriginUser) ||
+             !AGH_GBGETOBJ (GtkButton,         bSFRKProfileSaveOK) )
+                throw runtime_error ("Failed to construct SRK1968DialogWidgets");
+
+        mSFRKProfiles =
+                gtk_list_store_new( 1, G_TYPE_STRING);
+        gtk_combo_box_set_model_properly(
+                eSFRKProfileList, mSFRKProfiles);
+
+        G_CONNECT_2 (wSFRK, configure, event);
+        G_CONNECT_1 (wSFRK, show);
+        G_CONNECT_1 (wSFRK, hide);
+
+        eSFRKProfileList_changed_cb_handler_id =
+                G_CONNECT_1 (eSFRKProfileList, changed);
+        G_CONNECT_1 (bSFRKProfileSave,    clicked);
+        G_CONNECT_1 (bSFRKProfileRevert,  clicked);
+        G_CONNECT_1 (bSFRKProfileDiscard, clicked);
+
+        G_CONNECT_1 (bSFRKTry,    clicked);
+        G_CONNECT_1 (bSFRKModify, clicked);
+
+        G_CONNECT_1 (eSFRKProfileSaveName, changed);
+
+      // 2. dialog
+        W_V.reg( eSFRKNremThetaDeltaRatio, &Pp2.Pp.nrem3_delta_theta_ratio);
 }
 
+SScoringFacility::SRK1968Dialog::
+~SRK1968Dialog ()
+{
+        gtk_widget_destroy( (GtkWidget*)wSFRK);
+        g_object_unref( (GObject*)mSFRKProfiles);
+        g_object_unref( (GObject*)builder);
+}
 
 
 
diff --git a/upstream/src/aghermann/ui/sf/d/rk1968.hh b/upstream/src/aghermann/ui/sf/d/rk1968.hh
index a852a70..1f3f187 100644
--- a/upstream/src/aghermann/ui/sf/d/rk1968.hh
+++ b/upstream/src/aghermann/ui/sf/d/rk1968.hh
@@ -14,6 +14,7 @@
 
 #include "aghermann/rk1968/rk1968.hh"
 #include "aghermann/ui/ui++.hh"
+#include "aghermann/ui/dirlevel-storable-adapter.hh"
 #include "aghermann/ui/sf/sf.hh"
 
 #if HAVE_CONFIG_H && !defined(VERSION)
@@ -25,11 +26,20 @@ using namespace std;
 namespace agh {
 namespace ui {
 
-struct SRK1968DialogWidgets {
+struct SScoringFacility::SRK1968Dialog
+  : public SDirlevelStorableAdapter<agh::rk1968::CScoreAssistant> {
+
+        DELETE_DEFAULT_METHODS (SRK1968Dialog);
 
-        SRK1968DialogWidgets ();
-       ~SRK1968DialogWidgets ();
+      // ctor, dtor
+        explicit SRK1968Dialog (SScoringFacility&);
+       ~SRK1968Dialog ();
+
+      // parent
+        SScoringFacility&
+                _p;
 
+      // widgets
         GtkBuilder
                 *builder;
 
@@ -39,8 +49,8 @@ struct SRK1968DialogWidgets {
         GtkListStore
                 *mSFRKProfiles;
         GtkButton
-                *bSFRKProfileRevert,
                 *bSFRKProfileSave,
+                *bSFRKProfileRevert,
                 *bSFRKProfileDiscard;
         GtkComboBox
                 *eSFRKProfileList;
@@ -50,59 +60,47 @@ struct SRK1968DialogWidgets {
                 *eSFRKNremThetaDeltaRatio;
 
         GtkButton
-                *bSFRKRun,
+                *bSFRKTry,
                 *bSFRKModify;
         GtkLabel
                 *lSFRKWorking;
-};
 
+        GtkDialog
+                *wSFRKProfileSave;
+        GtkEntry
+                *eSFRKProfileSaveName;
+        GtkToggleButton
+                *eSFRKProfileSaveOriginSubject,
+                *eSFRKProfileSaveOriginExperiment,
+                *eSFRKProfileSaveOriginUser;
+        GtkButton
+                *bSFRKProfileSaveOK;
 
-struct SScoringFacility::SRK1968Dialog
-  : public SRK1968DialogWidgets {
-
-        DELETE_DEFAULT_METHODS (SRK1968Dialog);
+};
 
-      // ctor, dtor
-        explicit SRK1968Dialog (SScoringFacility&);
-       ~SRK1968Dialog ();
 
-      // saved profiles
-        list<agh::rk1968::CScoreAssistant>
-                profiles;
-        list<agh::rk1968::CScoreAssistant>::iterator
-                current_profile;
-        list<agh::rk1968::CScoreAssistant>::iterator
-        profile_by_idx( size_t);
+}} // namespace aghui
 
-        void load_profiles();
-        void save_profiles();
-        void discard_current_profile();
-        void populate_combo();
+extern "C" {
 
-      // widgets
-        SUIVarCollection
-                W_V;
-        void atomic_up()
-                {
-                        suppress_w_v = true;
-                        W_V.up();
-                        suppress_w_v = false;
-                }
+void eSFRKProfileList_changed_cb( GtkComboBox*, gpointer);
+void bSFRKProfileSave_clicked_cb( GtkButton*, gpointer);
+void bSFRKProfileDiscard_clicked_cb( GtkButton*, gpointer);
+void bSFRKProfileRevert_clicked_cb( GtkButton*, gpointer);
 
-        bool    suppress_w_v;
+void wSFRK_show_cb( GtkWidget*, gpointer);
+void wSFRK_hide_cb( GtkWidget*, gpointer);
+gboolean wSFRK_configure_event_cb( GtkWidget*, GdkEventConfigure*, gpointer);
 
-        SScoringFacility&
-                _p;
-};
 
+void bSFRKTry_clicked_cb( GtkButton*, gpointer);
+void bSFRKModify_clicked_cb( GtkButton*, gpointer);
 
-}} // namespace aghui
+void eSFRKProfileSaveName_changed_cb(GtkEditable*, gpointer);
 
-extern "C" {
-void eSFRKProfileList_changed_cb( GtkComboBox*, gpointer);
 }
 
-#endif // AGH_AGHERMANN_UI_SF_D_RK1968_H_
+#endif
 
 // Local Variables:
 // Mode: c++
diff --git a/upstream/src/aghermann/ui/sf/d/rk1968_cb.cc b/upstream/src/aghermann/ui/sf/d/rk1968_cb.cc
index 7b6cb54..e147d57 100644
--- a/upstream/src/aghermann/ui/sf/d/rk1968_cb.cc
+++ b/upstream/src/aghermann/ui/sf/d/rk1968_cb.cc
@@ -15,25 +15,67 @@ using namespace std;
 using namespace agh::ui;
 
 extern "C" {
-void eSFRKProfileList_changed_cb(
-        GtkComboBox* combo,
+
+gboolean
+wSFRK_configure_event_cb(
+        GtkWidget*,
+        GdkEventConfigure*,
+        gpointer userdata)
+{
+        auto& RK = *(SScoringFacility::SRK1968Dialog*)userdata;
+
+        return TRUE;
+}
+
+
+void
+wSFRK_show_cb(
+        GtkWidget*,
         gpointer userdata)
 {
         auto& RK = *(SScoringFacility::SRK1968Dialog*)userdata;
+        auto& SF = RK._p;
+
+        RK.load_profiles();
 
-        if ( RK.current_profile != RK.profiles.end() ) {
-                // RK.current_pattern-> = RK.;
-        }
-
-        gint ci = gtk_combo_box_get_active( combo);
-        if ( ci != -1 ) {
-                RK.current_profile = RK.profile_by_idx(ci);
-                //FD.Pp2 = FD.current_pattern->Pp;
-                RK.atomic_up();
-        }
-                //gtk_label_set_text( RK.lSFFDParametersBrief, "");
+        if ( RK.profiles.empty() )
+                RK.profiles.emplace_back(
+                        *RK._p._p.ED,
+                        agh::SExpDirLevelId {SF._p.ED->group_of(SF.csubject()), SF.csubject().id, SF.session()});
+
+        RK.populate_combo();
+        RK.set_profile_manage_buttons_visibility();
 }
 
+void
+wSFRK_hide_cb(
+        GtkWidget*,
+        gpointer userdata)
+{
+        auto& RK = *(SScoringFacility::SRK1968Dialog*)userdata;
+
+        RK.save_profiles();
+}
+
+void
+bSFRKTry_clicked_cb(
+        GtkButton*,
+        gpointer userdata)
+{
+        auto& RK = *(SScoringFacility::SRK1968Dialog*)userdata;
+
+        
+}
+
+void
+bSFRKModify_clicked_cb(
+        GtkButton*,
+        gpointer userdata)
+{
+        
+}
+
+
 } // extern "C"
 
 // Local Variables:

-- 
Alioth's /git/debian-med/git-commit-notice on /srv/git.debian.org/git/debian-med/aghermann.git



More information about the debian-med-commit mailing list