[niepce] rust: NiepceProperty is an enum



commit f868cc5ab9fd8bd5d4f1505742a6ccba89eb88cd
Author: Hubert Figuière <hub figuiere net>
Date:   Sat Feb 27 13:07:12 2021 -0500

    rust: NiepceProperty is an enum

 crates/npc-engine/build.rs                    |   6 ++
 crates/npc-engine/src/db/libfile.rs           |  35 ++++---
 crates/npc-engine/src/db/libmetadata.rs       |  36 ++++----
 crates/npc-engine/src/db/library.rs           |  17 ++--
 crates/npc-engine/src/db/mod.rs               |   2 +
 crates/npc-engine/src/db/props.rs             | 128 +++++++++++++++-----------
 crates/npc-engine/src/lib.rs                  |  84 +++++++++++++++++
 crates/npc-engine/src/library/commands.rs     |   2 +-
 crates/npc-engine/src/library/notification.rs |   8 +-
 crates/npc-fwk/src/base/mod.rs                |  23 +----
 crates/npc-fwk/src/base/propertybag.rs        |  71 ++------------
 crates/npc-fwk/src/base/propertyvalue.rs      |   5 +-
 niepce-main/build.rs                          |   1 +
 niepce-main/src/libraryclient/mod.rs          |   7 +-
 niepce-main/src/niepce/ui/image_list_store.rs |  16 ++--
 src/engine/db/properties-enum.hpp             |  22 -----
 src/engine/db/properties.cpp                  |  35 ++-----
 src/engine/db/properties.hpp                  |  10 +-
 src/fwk/base/propertybag.cpp                  |  20 ++--
 src/fwk/base/propertybag.hpp                  |   4 +-
 src/fwk/toolkit/metadatawidget.cpp            |  56 +++++------
 src/fwk/toolkit/metadatawidget.hpp            |  34 +++----
 src/niepce/modules/map/mapmodule.cpp          |   8 +-
 src/niepce/ui/metadatapanecontroller.cpp      | 110 +++++++++++-----------
 src/niepce/ui/metadatapanecontroller.hpp      |   2 +-
 src/niepce/ui/selectioncontroller.cpp         |  28 +++---
 src/niepce/ui/selectioncontroller.hpp         |   4 +-
 src/rust_bindings.hpp                         |  13 +--
 28 files changed, 398 insertions(+), 389 deletions(-)
---
diff --git a/crates/npc-engine/build.rs b/crates/npc-engine/build.rs
index 8565a72..27c5bbf 100644
--- a/crates/npc-engine/build.rs
+++ b/crates/npc-engine/build.rs
@@ -18,6 +18,7 @@ fn main() {
                 "strum",
             ])
             .include_item("Managed")
+            .include_item("NiepcePropertyIdx")
             .exclude_item("CUSTOM_START")
             .exclude_item("INTERNAL_START")
             .exclude_item("GdkPixbuf")
@@ -25,6 +26,11 @@ fn main() {
             .exclude_item("GtkToolbar")
             .exclude_item("GFileInfo")
             .exclude_item("RgbColour")
+            // Ensure these are opaque as generics are still a problem.
+            .exclude_item("NiepcePropertySet")
+            .exclude_item("NiepcePropertyBag")
+            .exclude_item("PropertySet")
+            .exclude_item("PropertyBag")
             .with_crate(&crate_dir)
             .generate()
             .expect("Couldn't generate bindings")
diff --git a/crates/npc-engine/src/db/libfile.rs b/crates/npc-engine/src/db/libfile.rs
index 60d4b6b..e023fc4 100644
--- a/crates/npc-engine/src/db/libfile.rs
+++ b/crates/npc-engine/src/db/libfile.rs
@@ -24,12 +24,11 @@ use std::ffi::CString;
 use std::path::{Path, PathBuf};
 
 use super::fsfile::FsFile;
-use super::props::np;
-use super::props::NiepceProperties as Np;
 use super::FromDb;
 use super::LibraryId;
+use super::NiepceProperties as Np;
+use super::NiepcePropertyIdx;
 use npc_fwk;
-use npc_fwk::base::PropertyIndex;
 
 #[repr(i32)]
 #[derive(Debug, Copy, Clone, PartialEq)]
@@ -195,21 +194,23 @@ impl LibFile {
     }
 
     pub fn property(&self, idx: Np) -> i32 {
+        use super::NiepcePropertyIdx::*;
         match idx {
-            np::NpTiffOrientationProp => self.orientation(),
-            np::NpXmpRatingProp => self.rating(),
-            np::NpXmpLabelProp => self.label(),
-            np::NpNiepceFlagProp => self.flag(),
+            Np::Index(NpTiffOrientationProp) => self.orientation(),
+            Np::Index(NpXmpRatingProp) => self.rating(),
+            Np::Index(NpXmpLabelProp) => self.label(),
+            Np::Index(NpNiepceFlagProp) => self.flag(),
             _ => -1,
         }
     }
 
     pub fn set_property(&mut self, idx: Np, value: i32) {
+        use super::NiepcePropertyIdx::*;
         match idx {
-            np::NpTiffOrientationProp => self.set_orientation(value),
-            np::NpXmpRatingProp => self.set_rating(value),
-            np::NpXmpLabelProp => self.set_label(value),
-            np::NpNiepceFlagProp => self.set_flag(value),
+            Np::Index(NpTiffOrientationProp) => self.set_orientation(value),
+            Np::Index(NpXmpRatingProp) => self.set_rating(value),
+            Np::Index(NpXmpLabelProp) => self.set_label(value),
+            Np::Index(NpNiepceFlagProp) => self.set_flag(value),
             _ => err_out!("invalid property {:?} - noop", idx),
         };
     }
@@ -319,8 +320,8 @@ pub extern "C" fn engine_db_libfile_orientation(obj: &LibFile) -> i32 {
 }
 
 #[no_mangle]
-pub extern "C" fn engine_db_libfile_property(obj: &LibFile, idx: PropertyIndex) -> i32 {
-    obj.property(idx)
+pub extern "C" fn engine_db_libfile_property(obj: &LibFile, idx: NiepcePropertyIdx) -> i32 {
+    obj.property(Np::Index(idx))
 }
 
 #[no_mangle]
@@ -329,6 +330,10 @@ pub extern "C" fn engine_db_libfile_file_type(obj: &LibFile) -> FileType {
 }
 
 #[no_mangle]
-pub extern "C" fn engine_db_libfile_set_property(obj: &mut LibFile, idx: PropertyIndex, v: i32) {
-    obj.set_property(idx, v);
+pub extern "C" fn engine_db_libfile_set_property(
+    obj: &mut LibFile,
+    idx: NiepcePropertyIdx,
+    v: i32,
+) {
+    obj.set_property(Np::Index(idx), v);
 }
diff --git a/crates/npc-engine/src/db/libmetadata.rs b/crates/npc-engine/src/db/libmetadata.rs
index d57b079..744d5f7 100644
--- a/crates/npc-engine/src/db/libmetadata.rs
+++ b/crates/npc-engine/src/db/libmetadata.rs
@@ -23,9 +23,9 @@ use rusqlite;
 
 use super::libfile::FileType;
 use super::props;
-use super::props::np::*;
-use super::props::NiepceProperties as Np;
+use super::NiepceProperties as Np;
 use super::{FromDb, LibraryId};
+use crate::{NiepcePropertyBag, NiepcePropertySet};
 use npc_fwk::utils::exempi::{NS_DC, NS_XAP};
 use npc_fwk::{xmp_date_from, PropertyBag, PropertySet, PropertyValue, XmpMeta};
 
@@ -187,32 +187,32 @@ impl LibMetadata {
         false
     }
 
-    pub fn to_properties(&self, propset: &PropertySet) -> PropertyBag {
+    pub fn to_properties(&self, propset: &PropertySet<Np>) -> PropertyBag<Np> {
+        use super::NiepcePropertyIdx::*;
         let mut props = PropertyBag::new();
         for prop_id in propset {
-            #[allow(non_upper_case_globals)]
             match *prop_id {
-                NpXmpRatingProp => {
+                Np::Index(NpXmpRatingProp) => {
                     if let Some(rating) = self.xmp.rating() {
                         props.set_value(*prop_id, PropertyValue::Int(rating));
                     }
                 }
-                NpXmpLabelProp => {
+                Np::Index(NpXmpLabelProp) => {
                     if let Some(label) = self.xmp.label() {
                         props.set_value(*prop_id, PropertyValue::String(label));
                     }
                 }
-                NpTiffOrientationProp => {
+                Np::Index(NpTiffOrientationProp) => {
                     if let Some(orientation) = self.xmp.orientation() {
                         props.set_value(*prop_id, PropertyValue::Int(orientation));
                     }
                 }
-                NpExifDateTimeOriginalProp => {
+                Np::Index(NpExifDateTimeOriginalProp) => {
                     if let Some(date) = self.xmp.creation_date() {
                         props.set_value(*prop_id, PropertyValue::Date(date));
                     }
                 }
-                NpIptcKeywordsProp => {
+                Np::Index(NpIptcKeywordsProp) => {
                     let mut iter = exempi::XmpIterator::new(
                         &self.xmp.xmp,
                         NS_DC,
@@ -229,25 +229,25 @@ impl LibMetadata {
                     }
                     props.set_value(*prop_id, PropertyValue::StringArray(keywords));
                 }
-                NpFileNameProp => {
+                Np::Index(NpFileNameProp) => {
                     props.set_value(*prop_id, PropertyValue::String(self.name.clone()));
                 }
-                NpFileTypeProp => {
+                Np::Index(NpFileTypeProp) => {
                     let file_type: &str = self.file_type.into();
                     props.set_value(*prop_id, PropertyValue::String(String::from(file_type)));
                 }
-                NpFileSizeProp => {}
-                NpFolderProp => {
+                Np::Index(NpFileSizeProp) => {}
+                Np::Index(NpFolderProp) => {
                     props.set_value(*prop_id, PropertyValue::String(self.folder.clone()));
                 }
-                NpSidecarsProp => {
+                Np::Index(NpSidecarsProp) => {
                     props.set_value(*prop_id, PropertyValue::StringArray(self.sidecars.clone()));
                 }
                 _ => {
-                    if let Some(propval) = self.get_metadata(*prop_id) {
+                    if let Some(propval) = self.get_metadata((*prop_id).into()) {
                         props.set_value(*prop_id, propval);
                     } else {
-                        dbg_out!("missing prop {}", prop_id);
+                        dbg_out!("missing prop {:?}", prop_id);
                     }
                 }
             }
@@ -300,8 +300,8 @@ pub extern "C" fn engine_libmetadata_get_id(meta: &LibMetadata) -> LibraryId {
 #[no_mangle]
 pub extern "C" fn engine_libmetadata_to_properties(
     meta: &LibMetadata,
-    propset: &PropertySet,
-) -> *mut PropertyBag {
+    propset: &NiepcePropertySet,
+) -> *mut NiepcePropertyBag {
     let result = Box::new(meta.to_properties(propset));
     Box::into_raw(result)
 }
diff --git a/crates/npc-engine/src/db/library.rs b/crates/npc-engine/src/db/library.rs
index 4618005..d53242c 100644
--- a/crates/npc-engine/src/db/library.rs
+++ b/crates/npc-engine/src/db/library.rs
@@ -27,8 +27,8 @@ use std::sync::mpsc;
 use chrono::Utc;
 use rusqlite;
 
-use super::props::np::*;
 use super::props::NiepceProperties as Np;
+use super::props::NiepcePropertyIdx::*;
 use super::{FromDb, LibraryId};
 use crate::db::filebundle::{FileBundle, Sidecar};
 use crate::db::keyword::Keyword;
@@ -884,16 +884,19 @@ impl Library {
     pub fn set_metadata(&self, file_id: LibraryId, meta: Np, value: &PropertyValue) -> Result<()> {
         #[allow(non_upper_case_globals)]
         match meta {
-            NpXmpRatingProp | NpXmpLabelProp | NpTiffOrientationProp | NpNiepceFlagProp => {
+            Np::Index(NpXmpRatingProp)
+            | Np::Index(NpXmpLabelProp)
+            | Np::Index(NpTiffOrientationProp)
+            | Np::Index(NpNiepceFlagProp) => {
                 match *value {
                     PropertyValue::Int(i) => {
                         // internal
                         // make the column mapping more generic.
                         let column = match meta {
-                            NpXmpRatingProp => "rating",
-                            NpXmpLabelProp => "label",
-                            NpTiffOrientationProp => "orientation",
-                            NpNiepceFlagProp => "flag",
+                            Np::Index(NpXmpRatingProp) => "rating",
+                            Np::Index(NpXmpLabelProp) => "label",
+                            Np::Index(NpTiffOrientationProp) => "orientation",
+                            Np::Index(NpNiepceFlagProp) => "flag",
                             _ => unreachable!(),
                         };
                         if !column.is_empty() {
@@ -903,7 +906,7 @@ impl Library {
                     _ => err_out!("improper value type for {:?}", meta),
                 }
             }
-            NpIptcKeywordsProp => {
+            Np::Index(NpIptcKeywordsProp) => {
                 self.unassign_all_keywords_for_file(file_id)?;
 
                 match *value {
diff --git a/crates/npc-engine/src/db/mod.rs b/crates/npc-engine/src/db/mod.rs
index 1a03ccb..2d21ff2 100644
--- a/crates/npc-engine/src/db/mod.rs
+++ b/crates/npc-engine/src/db/mod.rs
@@ -35,6 +35,8 @@ pub use self::label::Label;
 pub use self::libfolder::LibFolder;
 pub use self::libmetadata::LibMetadata;
 pub use self::library::Library;
+pub use self::props::NiepceProperties;
+pub use self::props::NiepcePropertyIdx;
 
 use rusqlite;
 
diff --git a/crates/npc-engine/src/db/props.rs b/crates/npc-engine/src/db/props.rs
index 4789ef3..e4716a3 100644
--- a/crates/npc-engine/src/db/props.rs
+++ b/crates/npc-engine/src/db/props.rs
@@ -5,63 +5,83 @@ use npc_fwk::utils::exempi::{NS_DC, NS_EXIF, NS_PHOTOSHOP, NS_TIFF, NS_XAP};
 mod xmp {
     pub use npc_fwk::utils::exempi::NIEPCE_XMP_NAMESPACE;
 }
-
-pub type NiepceProperties = u32;
-
-#[allow(non_upper_case_globals)]
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[repr(u32)]
+pub enum NiepcePropertyIdx {
+    NpFileNameProp,
+    NpFileTypeProp,
+    NpFileSizeProp,
+    NpFolderProp,
+    NpSidecarsProp,
+    NpXmpRatingProp,
+    NpXmpLabelProp,
+    NpTiffOrientationProp,
+    NpTiffMakeProp,
+    NpTiffModelProp,
+    NpExifAuxLensProp,
+    NpExifExposureProgramProp,
+    NpExifExposureTimeProp,
+    NpExifFNumberPropProp,
+    NpExifIsoSpeedRatingsProp,
+    NpExifExposureBiasProp,
+    NpExifFlashFiredProp,
+    NpExifAuxFlashCompensationProp,
+    NpExifWbProp,
+    NpExifDateTimeOriginalProp,
+    NpExifFocalLengthProp,
+    NpExifGpsLongProp,
+    NpExifGpsLatProp,
+    NpIptcHeadlineProp,
+    NpIptcDescriptionProp,
+    NpIptcKeywordsProp,
+    NpNiepceFlagProp,
+}
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
 #[allow(unused_parens)]
-pub mod np {
-    pub const NpFileNameProp: u32 = (0x0f00 << 16 | 0);
-    pub const NpFileTypeProp: u32 = (0x0f00 << 16 | 1);
-    pub const NpFileSizeProp: u32 = (0x0f00 << 16 | 2);
-    pub const NpFolderProp: u32 = (0x0f00 << 16 | 3);
-    pub const NpSidecarsProp: u32 = (0x0f00 << 16 | 4);
-    pub const NpXmpRatingProp: u32 = (0 << 16 | 1);
-    pub const NpXmpLabelProp: u32 = (0 << 16 | 2);
-    pub const NpTiffOrientationProp: u32 = (1 << 16 | 0);
-    pub const NpTiffMakeProp: u32 = (1 << 16 | 1);
-    pub const NpTiffModelProp: u32 = (1 << 16 | 2);
-    pub const NpExifAuxLensProp: u32 = (2 << 16 | 0);
-    pub const NpExifExposureProgramProp: u32 = (2 << 16 | 1);
-    pub const NpExifExposureTimeProp: u32 = (2 << 16 | 2);
-    pub const NpExifFNumberPropProp: u32 = (2 << 16 | 3);
-    pub const NpExifIsoSpeedRatingsProp: u32 = (2 << 16 | 4);
-    pub const NpExifExposureBiasProp: u32 = (2 << 16 | 5);
-    pub const NpExifFlashFiredProp: u32 = (2 << 16 | 6);
-    pub const NpExifAuxFlashCompensationProp: u32 = (2 << 16 | 7);
-    pub const NpExifWbProp: u32 = (2 << 16 | 8);
-    pub const NpExifDateTimeOriginalProp: u32 = (2 << 16 | 9);
-    pub const NpExifFocalLengthProp: u32 = (2 << 16 | 10);
-    pub const NpExifGpsLongProp: u32 = (2 << 16 | 11);
-    pub const NpExifGpsLatProp: u32 = (2 << 16 | 12);
-    pub const NpIptcHeadlineProp: u32 = (3 << 16 | 0);
-    pub const NpIptcDescriptionProp: u32 = (3 << 16 | 1);
-    pub const NpIptcKeywordsProp: u32 = (3 << 16 | 2);
-    pub const NpNiepceFlagProp: u32 = (4 << 16 | 0);
+#[repr(C)]
+pub enum NiepceProperties {
+    Index(NiepcePropertyIdx),
+    Other(u32),
+}
+impl Into<u32> for NiepceProperties {
+    fn into(self) -> u32 {
+        match self {
+            Self::Index(i) => i as u32,
+            Self::Other(i) => i,
+        }
+    }
+}
+impl From<u32> for NiepceProperties {
+    fn from(v: u32) -> NiepceProperties {
+        match v {
+            0..=26 => Self::Index(unsafe { std::mem::transmute(v) }),
+            _ => Self::Other(v),
+        }
+    }
 }
 lazy_static! {
     pub static ref PROP_TO_XMP_MAP: std::collections::HashMap<NiepceProperties, (&'static str, &'static 
str)> = hashmap! {
-    np::NpXmpRatingProp => (NS_XAP, "Rating"),
-    np::NpXmpLabelProp => (NS_XAP, "Label"),
-    np::NpTiffOrientationProp => (NS_TIFF, "Orientation"),
-    np::NpTiffMakeProp => (NS_TIFF, "Make"),
-    np::NpTiffModelProp => (NS_TIFF, "Model"),
-    np::NpExifAuxLensProp => (NS_EXIF_AUX, "Lens"),
-    np::NpExifExposureProgramProp => (NS_EXIF, "ExposureProgram"),
-    np::NpExifExposureTimeProp => (NS_EXIF, "ExposureTime"),
-    np::NpExifFNumberPropProp => (NS_EXIF, "FNumber"),
-    np::NpExifIsoSpeedRatingsProp => (NS_EXIF, "ISOSpeedRatings"),
-    np::NpExifExposureBiasProp => (NS_EXIF, "ExposureBiasValue"),
-    np::NpExifFlashFiredProp => (NS_EXIF, "Flash/exif:Fired"),
-    np::NpExifAuxFlashCompensationProp => (NS_EXIF_AUX, "FlashCompensation"),
-    np::NpExifWbProp => (NS_EXIF, "WhiteBalance"),
-    np::NpExifDateTimeOriginalProp => (NS_EXIF, "DateTimeOriginal"),
-    np::NpExifFocalLengthProp => (NS_EXIF, "FocalLength"),
-    np::NpExifGpsLongProp => (NS_EXIF, "GPSLongitude"),
-    np::NpExifGpsLatProp => (NS_EXIF, "GPSLatitude"),
-    np::NpIptcHeadlineProp => (NS_PHOTOSHOP, "Headline"),
-    np::NpIptcDescriptionProp => (NS_DC, "description"),
-    np::NpIptcKeywordsProp => (NS_DC, "subject"),
-    np::NpNiepceFlagProp => (xmp::NIEPCE_XMP_NAMESPACE, "Flag"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpXmpRatingProp) => (NS_XAP, "Rating"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpXmpLabelProp) => (NS_XAP, "Label"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpTiffOrientationProp) => (NS_TIFF, "Orientation"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpTiffMakeProp) => (NS_TIFF, "Make"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpTiffModelProp) => (NS_TIFF, "Model"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifAuxLensProp) => (NS_EXIF_AUX, "Lens"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifExposureProgramProp) => (NS_EXIF, "ExposureProgram"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifExposureTimeProp) => (NS_EXIF, "ExposureTime"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifFNumberPropProp) => (NS_EXIF, "FNumber"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifIsoSpeedRatingsProp) => (NS_EXIF, "ISOSpeedRatings"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifExposureBiasProp) => (NS_EXIF, "ExposureBiasValue"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifFlashFiredProp) => (NS_EXIF, "Flash/exif:Fired"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifAuxFlashCompensationProp) => (NS_EXIF_AUX, 
"FlashCompensation"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifWbProp) => (NS_EXIF, "WhiteBalance"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifDateTimeOriginalProp) => (NS_EXIF, "DateTimeOriginal"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifFocalLengthProp) => (NS_EXIF, "FocalLength"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifGpsLongProp) => (NS_EXIF, "GPSLongitude"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpExifGpsLatProp) => (NS_EXIF, "GPSLatitude"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpIptcHeadlineProp) => (NS_PHOTOSHOP, "Headline"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpIptcDescriptionProp) => (NS_DC, "description"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpIptcKeywordsProp) => (NS_DC, "subject"),
+    NiepceProperties::Index(NiepcePropertyIdx::NpNiepceFlagProp) => (xmp::NIEPCE_XMP_NAMESPACE, "Flag"),
     };
 }
diff --git a/crates/npc-engine/src/lib.rs b/crates/npc-engine/src/lib.rs
index 660ab4c..86d0598 100644
--- a/crates/npc-engine/src/lib.rs
+++ b/crates/npc-engine/src/lib.rs
@@ -28,3 +28,87 @@ extern crate npc_fwk;
 
 pub mod db;
 pub mod library;
+
+use std::ptr;
+
+use npc_fwk::base::PropertyIndex;
+use npc_fwk::PropertyValue;
+
+use db::{NiepceProperties, NiepcePropertyIdx};
+
+type NiepcePropertySet = npc_fwk::PropertySet<db::NiepceProperties>;
+type NiepcePropertyBag = npc_fwk::PropertyBag<db::NiepceProperties>;
+
+#[no_mangle]
+pub extern "C" fn eng_property_set_new() -> *mut NiepcePropertySet {
+    Box::into_raw(Box::new(NiepcePropertySet::new()))
+}
+
+/// Delete a %PropertySet
+///
+/// # Safety
+/// Dereference the pointer.
+#[no_mangle]
+pub unsafe extern "C" fn eng_property_set_delete(set: *mut NiepcePropertySet) {
+    Box::from_raw(set);
+}
+
+#[no_mangle]
+pub extern "C" fn eng_property_set_add(set: &mut NiepcePropertySet, v: NiepcePropertyIdx) {
+    set.insert(NiepceProperties::Index(v));
+}
+
+#[no_mangle]
+pub extern "C" fn eng_property_bag_new() -> *mut NiepcePropertyBag {
+    Box::into_raw(Box::new(NiepcePropertyBag::new()))
+}
+
+/// Delete the %PropertyBag object
+///
+/// # Safety
+/// Dereference the raw pointer.
+#[no_mangle]
+pub unsafe extern "C" fn eng_property_bag_delete(bag: *mut NiepcePropertyBag) {
+    Box::from_raw(bag);
+}
+
+#[no_mangle]
+pub extern "C" fn eng_property_bag_is_empty(b: &NiepcePropertyBag) -> bool {
+    b.is_empty()
+}
+
+#[no_mangle]
+pub extern "C" fn eng_property_bag_len(b: &NiepcePropertyBag) -> usize {
+    b.len()
+}
+
+#[no_mangle]
+pub extern "C" fn eng_property_bag_key_by_index(
+    b: &NiepcePropertyBag,
+    idx: usize,
+) -> PropertyIndex {
+    b.bag[idx].into()
+}
+
+#[no_mangle]
+pub extern "C" fn eng_property_bag_value(
+    b: &NiepcePropertyBag,
+    key: PropertyIndex,
+) -> *mut PropertyValue {
+    let key: db::NiepceProperties = key.into();
+    if b.map.contains_key(&key) {
+        let value = Box::new(b.map[&key].clone());
+        Box::into_raw(value)
+    } else {
+        ptr::null_mut()
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn eng_property_bag_set_value(
+    b: &mut NiepcePropertyBag,
+    key: PropertyIndex,
+    v: &PropertyValue,
+) -> bool {
+    b.set_value(key.into(), v.clone())
+}
diff --git a/crates/npc-engine/src/library/commands.rs b/crates/npc-engine/src/library/commands.rs
index 826791b..2f3166c 100644
--- a/crates/npc-engine/src/library/commands.rs
+++ b/crates/npc-engine/src/library/commands.rs
@@ -215,7 +215,7 @@ pub fn cmd_set_metadata(lib: &Library, id: LibraryId, meta: Np, value: &Property
             if lib
                 .notify(LibNotification::MetadataChanged(MetadataChange::new(
                     id,
-                    meta as u32,
+                    meta.into(),
                     value.clone(),
                 )))
                 .is_err()
diff --git a/crates/npc-engine/src/library/notification.rs b/crates/npc-engine/src/library/notification.rs
index b72383f..9c0dc15 100644
--- a/crates/npc-engine/src/library/notification.rs
+++ b/crates/npc-engine/src/library/notification.rs
@@ -19,7 +19,7 @@
 
 use super::queriedcontent::QueriedContent;
 use crate::db::libfile::FileStatus;
-use crate::db::{Keyword, Label, LibFolder, LibMetadata, LibraryId};
+use crate::db::{Keyword, Label, LibFolder, LibMetadata, LibraryId, NiepceProperties};
 use npc_fwk::base::PropertyIndex;
 use npc_fwk::toolkit::thumbnail;
 use npc_fwk::toolkit::PortableChannel;
@@ -79,12 +79,12 @@ pub struct Count {
 #[derive(Clone)]
 pub struct MetadataChange {
     pub id: LibraryId,
-    pub meta: PropertyIndex,
+    pub meta: NiepceProperties,
     pub value: PropertyValue,
 }
 
 impl MetadataChange {
-    pub fn new(id: LibraryId, meta: PropertyIndex, value: PropertyValue) -> Self {
+    pub fn new(id: LibraryId, meta: NiepceProperties, value: PropertyValue) -> Self {
         MetadataChange { id, meta, value }
     }
 }
@@ -105,7 +105,7 @@ pub unsafe extern "C" fn metadatachange_get_id(meta: *const MetadataChange) -> L
 
 #[no_mangle]
 pub unsafe extern "C" fn metadatachange_get_meta(meta: *const MetadataChange) -> PropertyIndex {
-    (*meta).meta
+    (*meta).meta.into()
 }
 
 #[no_mangle]
diff --git a/crates/npc-fwk/src/base/mod.rs b/crates/npc-fwk/src/base/mod.rs
index 8c334c4..070f61a 100644
--- a/crates/npc-fwk/src/base/mod.rs
+++ b/crates/npc-fwk/src/base/mod.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/base/mod.rs
  *
- * Copyright (C) 2017-2018 Hubert Figuière
+ * Copyright (C) 2017-2021 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -29,25 +29,6 @@ pub mod propertyvalue;
 pub mod rgbcolour;
 
 pub type PropertyIndex = u32;
-pub type PropertySet = BTreeSet<PropertyIndex>;
+pub type PropertySet<T> = BTreeSet<T>;
 
 pub use self::propertyvalue::PropertyValue;
-
-#[no_mangle]
-pub extern "C" fn fwk_property_set_new() -> *mut PropertySet {
-    Box::into_raw(Box::new(PropertySet::new()))
-}
-
-/// Delete a %PropertySet
-///
-/// # Safety
-/// Dereference the pointer.
-#[no_mangle]
-pub unsafe extern "C" fn fwk_property_set_delete(set: *mut PropertySet) {
-    Box::from_raw(set);
-}
-
-#[no_mangle]
-pub extern "C" fn fwk_property_set_add(set: &mut PropertySet, v: PropertyIndex) {
-    set.insert(v);
-}
diff --git a/crates/npc-fwk/src/base/propertybag.rs b/crates/npc-fwk/src/base/propertybag.rs
index 967498a..f036c38 100644
--- a/crates/npc-fwk/src/base/propertybag.rs
+++ b/crates/npc-fwk/src/base/propertybag.rs
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/base/propertybag.rs
  *
- * Copyright (C) 2017-2018 Hubert Figuière
+ * Copyright (C) 2017-2021 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -18,20 +18,20 @@
  */
 
 use std::collections::BTreeMap;
-use std::ptr;
 
 use crate::base::propertyvalue::PropertyValue;
-use crate::base::PropertyIndex;
 
-#[derive(Default)]
-pub struct PropertyBag {
-    pub bag: Vec<PropertyIndex>,
-    pub map: BTreeMap<PropertyIndex, PropertyValue>,
+pub struct PropertyBag<Index> {
+    pub bag: Vec<Index>,
+    pub map: BTreeMap<Index, PropertyValue>,
 }
 
-impl PropertyBag {
+impl<Index: Ord + Copy> PropertyBag<Index> {
     pub fn new() -> Self {
-        PropertyBag::default()
+        Self {
+            bag: vec![],
+            map: BTreeMap::new(),
+        }
     }
 
     pub fn is_empty(&self) -> bool {
@@ -42,7 +42,7 @@ impl PropertyBag {
         self.bag.len()
     }
 
-    pub fn set_value(&mut self, key: PropertyIndex, value: PropertyValue) -> bool {
+    pub fn set_value(&mut self, key: Index, value: PropertyValue) -> bool {
         let ret = self.map.insert(key, value);
         if ret.is_some() {
             return true;
@@ -51,54 +51,3 @@ impl PropertyBag {
         false
     }
 }
-
-#[no_mangle]
-pub extern "C" fn fwk_property_bag_new() -> *mut PropertyBag {
-    Box::into_raw(Box::new(PropertyBag::new()))
-}
-
-/// Delete the %PropertyBag object
-///
-/// # Safety
-/// Dereference the raw pointer.
-#[no_mangle]
-pub unsafe extern "C" fn fwk_property_bag_delete(bag: *mut PropertyBag) {
-    Box::from_raw(bag);
-}
-
-#[no_mangle]
-pub extern "C" fn fwk_property_bag_is_empty(b: &PropertyBag) -> bool {
-    b.is_empty()
-}
-
-#[no_mangle]
-pub extern "C" fn fwk_property_bag_len(b: &PropertyBag) -> usize {
-    b.len()
-}
-
-#[no_mangle]
-pub extern "C" fn fwk_property_bag_key_by_index(b: &PropertyBag, idx: usize) -> PropertyIndex {
-    b.bag[idx]
-}
-
-#[no_mangle]
-pub extern "C" fn fwk_property_bag_value(
-    b: &PropertyBag,
-    key: PropertyIndex,
-) -> *mut PropertyValue {
-    if b.map.contains_key(&key) {
-        let value = Box::new(b.map[&key].clone());
-        Box::into_raw(value)
-    } else {
-        ptr::null_mut()
-    }
-}
-
-#[no_mangle]
-pub extern "C" fn fwk_property_bag_set_value(
-    b: &mut PropertyBag,
-    key: PropertyIndex,
-    v: &PropertyValue,
-) -> bool {
-    b.set_value(key, v.clone())
-}
diff --git a/crates/npc-fwk/src/base/propertyvalue.rs b/crates/npc-fwk/src/base/propertyvalue.rs
index 9e96ccf..186c5ba 100644
--- a/crates/npc-fwk/src/base/propertyvalue.rs
+++ b/crates/npc-fwk/src/base/propertyvalue.rs
@@ -85,7 +85,10 @@ pub extern "C" fn fwk_property_value_is_empty(v: &PropertyValue) -> bool {
 pub extern "C" fn fwk_property_value_is_integer(v: &PropertyValue) -> bool {
     match *v {
         PropertyValue::Int(_) => true,
-        _ => false,
+        _ => {
+            println!("PropertyValue is {:?}", &v);
+            false
+        }
     }
 }
 
diff --git a/niepce-main/build.rs b/niepce-main/build.rs
index 18fb70b..47f0151 100644
--- a/niepce-main/build.rs
+++ b/niepce-main/build.rs
@@ -21,6 +21,7 @@ fn main() {
             ])
             .include_item("ColIndex")
             .exclude_item("Managed")
+            .exclude_item("NiepcePropertyIdx")
             .exclude_item("FileStatus")
             .exclude_item("RgbColour")
             .exclude_item("CUSTOM_START")
diff --git a/niepce-main/src/libraryclient/mod.rs b/niepce-main/src/libraryclient/mod.rs
index e199381..ecda516 100644
--- a/niepce-main/src/libraryclient/mod.rs
+++ b/niepce-main/src/libraryclient/mod.rs
@@ -31,6 +31,7 @@ use self::clientimpl::ClientImpl;
 use npc_engine::db::library::Managed;
 use npc_engine::db::props::NiepceProperties as Np;
 use npc_engine::db::LibraryId;
+use npc_engine::db::{NiepceProperties, NiepcePropertyIdx};
 use npc_engine::library::notification::{LcChannel, LibNotification};
 use npc_fwk::base::PropertyValue;
 use npc_fwk::toolkit::PortableChannel;
@@ -292,10 +293,12 @@ pub extern "C" fn libraryclient_request_metadata(
 pub extern "C" fn libraryclient_set_metadata(
     client: &mut LibraryClientWrapper,
     file_id: LibraryId,
-    meta: Np,
+    meta: NiepcePropertyIdx,
     value: &PropertyValue,
 ) {
-    client.unwrap_mut().set_metadata(file_id, meta, value);
+    client
+        .unwrap_mut()
+        .set_metadata(file_id, NiepceProperties::Index(meta), value);
 }
 
 #[no_mangle]
diff --git a/niepce-main/src/niepce/ui/image_list_store.rs b/niepce-main/src/niepce/ui/image_list_store.rs
index 59ef377..0c9ebd6 100644
--- a/niepce-main/src/niepce/ui/image_list_store.rs
+++ b/niepce-main/src/niepce/ui/image_list_store.rs
@@ -31,11 +31,11 @@ use gtk_sys;
 use once_cell::unsync::OnceCell;
 
 use npc_engine::db::libfile::{FileStatus, LibFile};
-use npc_engine::db::props::np;
+use npc_engine::db::props::NiepceProperties as Np;
+use npc_engine::db::props::NiepcePropertyIdx::*;
 use npc_engine::db::LibraryId;
 use npc_engine::library::notification::{LibNotification, MetadataChange};
 use npc_engine::library::thumbnail_cache::ThumbnailCache;
-use npc_fwk::base::PropertyIndex;
 use npc_fwk::toolkit::gdk_utils;
 use npc_fwk::PropertyValue;
 
@@ -100,11 +100,11 @@ impl ImageListStore {
             .as_ref()
     }
 
-    fn is_property_interesting(idx: PropertyIndex) -> bool {
-        return (idx == np::NpXmpRatingProp)
-            || (idx == np::NpXmpLabelProp)
-            || (idx == np::NpTiffOrientationProp)
-            || (idx == np::NpNiepceFlagProp);
+    fn is_property_interesting(idx: Np) -> bool {
+        return (idx == Np::Index(NpXmpRatingProp))
+            || (idx == Np::Index(NpXmpLabelProp))
+            || (idx == Np::Index(NpTiffOrientationProp))
+            || (idx == Np::Index(NpNiepceFlagProp));
     }
 
     fn get_iter_from_id(&self, id: LibraryId) -> Option<&gtk::TreeIter> {
@@ -190,7 +190,7 @@ impl ImageListStore {
                 true
             }
             MetadataChanged(ref m) => {
-                dbg_out!("metadata changed {}", m.meta);
+                dbg_out!("metadata changed {:?}", m.meta);
                 // only interested in a few props
                 if Self::is_property_interesting(m.meta) {
                     if let Some(iter) = self.idmap.get(&m.id) {
diff --git a/src/engine/db/properties.cpp b/src/engine/db/properties.cpp
index e5e9bcd..9821641 100644
--- a/src/engine/db/properties.cpp
+++ b/src/engine/db/properties.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - eng/db/properties.cpp
  *
- * Copyright (C) 2011 Hubert Figuiere
+ * Copyright (C) 2011-2021 Hubert Figuiere
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,54 +19,37 @@
 
 #include "properties.hpp"
 
+#include "rust_bindings.hpp"
 
 namespace eng {
 
 #define DEFINE_PROPERTY(a,b,c,d,e)               \
-    { a, #a, typeid(e) },
+    { NiepcePropertyIdx::a, { NiepcePropertyIdx::a, #a, typeid(e) } },
 
-static const property_desc_t properties_names[] = {
+static const PropDescMap propmap = {
 
     #include "engine/db/properties-def.hpp"
 
-    { 0, NULL, typeid(NULL) }
 };
 
 #undef DEFINE_PROPERTY
 
-const char * _propertyName(fwk::PropertyIndex idx)
+const char * _propertyName(eng::NiepcePropertyIdx idx)
 {
-    const PropDescMap & propmap = property_desc_map();
     PropDescMap::const_iterator iter = propmap.find(idx);
     if(iter != propmap.end()) {
-        if(iter->second->name) {
-            return iter->second->name;
+        if(iter->second.name) {
+            return iter->second.name;
         }
     }
     return "UNKNOWN";
 }
 
-const PropDescMap & property_desc_map()
+bool check_property_type(eng::NiepcePropertyIdx idx, const std::type_info & ti)
 {
-    static PropDescMap s_map;
-    if(s_map.empty()) {
-        const eng::property_desc_t * current = eng::properties_names;
-        while(current->prop != 0) {
-            if(current->name) {
-                s_map.insert(std::make_pair(current->prop, current));
-            }
-            ++current;
-        }
-    }
-    return s_map;
-}
-
-bool check_property_type(fwk::PropertyIndex idx, const std::type_info & ti)
-{
-    const PropDescMap & propmap = property_desc_map();
     PropDescMap::const_iterator iter = propmap.find(idx);
     if(iter != propmap.end()) {
-        return iter->second->type == ti;
+        return iter->second.type == ti;
     }
     // we don't know the type. Assume it is OK
     return true;
diff --git a/src/engine/db/properties.hpp b/src/engine/db/properties.hpp
index 594b746..ea93300 100644
--- a/src/engine/db/properties.hpp
+++ b/src/engine/db/properties.hpp
@@ -26,23 +26,19 @@
 #include "fwk/base/propertybag.hpp"
 #include "engine/db/metadata.hpp"
 
-#include "engine/db/properties-enum.hpp"
-
 namespace eng {
 
 
 struct property_desc_t {
-    fwk::PropertyIndex prop;
+    eng::NiepcePropertyIdx prop;
     const char * name;
     const std::type_info & type;
 };
 
-typedef std::map<fwk::PropertyIndex, const property_desc_t*> PropDescMap;
+typedef std::map<eng::NiepcePropertyIdx, const property_desc_t> PropDescMap;
 
-/** get the properties description */
-const PropDescMap & property_desc_map();
 /** return true of the property is of the type ti */
-bool check_property_type(fwk::PropertyIndex idx, const std::type_info & ti);
+bool check_property_type(eng::NiepcePropertyIdx idx, const std::type_info & ti);
 
 
 /** internal property name */
diff --git a/src/fwk/base/propertybag.cpp b/src/fwk/base/propertybag.cpp
index d32b77b..7b78087 100644
--- a/src/fwk/base/propertybag.cpp
+++ b/src/fwk/base/propertybag.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/base/propertybag.cpp
  *
- * Copyright (C) 2011-2020 Hubert Figuière
+ * Copyright (C) 2011-2021 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,12 +26,12 @@ namespace fwk {
 
 PropertySetPtr property_set_wrap(PropertySet* s)
 {
-    return PropertySetPtr(s, &ffi::fwk_property_set_delete);
+    return PropertySetPtr(s, &ffi::eng_property_set_delete);
 }
 
 PropertySetPtr property_set_new()
 {
-    return property_set_wrap(ffi::fwk_property_set_new());
+    return property_set_wrap(ffi::eng_property_set_new());
 }
 
 PropertyValuePtr property_value_wrap(PropertyValue* v)
@@ -82,30 +82,30 @@ std::vector<std::string> property_value_get_string_array(const PropertyValue &va
 
 PropertyBagPtr property_bag_wrap(PropertyBag* bag)
 {
-    return PropertyBagPtr(bag, &ffi::fwk_property_bag_delete);
+    return PropertyBagPtr(bag, &ffi::eng_property_bag_delete);
 }
 
 PropertyBagPtr property_bag_new()
 {
-    return property_bag_wrap(ffi::fwk_property_bag_new());
+    return property_bag_wrap(ffi::eng_property_bag_new());
 }
 
 PropertyValuePtr property_bag_value(const PropertyBagPtr& bag, PropertyIndex idx)
 {
-    auto value = ffi::fwk_property_bag_value(bag.get(), idx);
+    auto value = ffi::eng_property_bag_value(bag.get(), idx);
     return property_value_wrap(value);
 }
 
-bool set_value_for_property(PropertyBag& bag, PropertyIndex idx,
+bool set_value_for_property(PropertyBag& bag, ffi::NiepcePropertyIdx idx,
                             const PropertyValue & value)
 {
-    return ffi::fwk_property_bag_set_value(&bag, idx, &value);
+    return ffi::eng_property_bag_set_value(&bag, static_cast<uint32_t>(idx), &value);
 }
 
 fwk::Option<PropertyValuePtr> get_value_for_property(const PropertyBag& bag,
-                                                     PropertyIndex idx)
+                                                     ffi::NiepcePropertyIdx idx)
 {
-    auto value = ffi::fwk_property_bag_value(&bag, idx);
+    auto value = ffi::eng_property_bag_value(&bag, static_cast<uint32_t>(idx));
     if (!value) {
         return fwk::Option<PropertyValuePtr>();
     }
diff --git a/src/fwk/base/propertybag.hpp b/src/fwk/base/propertybag.hpp
index d3ed7ad..74e9f4e 100644
--- a/src/fwk/base/propertybag.hpp
+++ b/src/fwk/base/propertybag.hpp
@@ -62,9 +62,9 @@ PropertyValuePtr property_bag_value(const PropertyBagPtr& bag, PropertyIndex key
 std::string property_value_get_string(const PropertyValue& v);
 
 /** return true if a property was removed prior to insertion */
-bool set_value_for_property(PropertyBag&, PropertyIndex idx, const PropertyValue & value);
+bool set_value_for_property(PropertyBag&, ffi::NiepcePropertyIdx idx, const PropertyValue & value);
 /** return property or an empty option */
-fwk::Option<PropertyValuePtr> get_value_for_property(const PropertyBag&, PropertyIndex idx);
+fwk::Option<PropertyValuePtr> get_value_for_property(const PropertyBag&, ffi::NiepcePropertyIdx idx);
 
 }
 
diff --git a/src/fwk/toolkit/metadatawidget.cpp b/src/fwk/toolkit/metadatawidget.cpp
index 776aead..417a320 100644
--- a/src/fwk/toolkit/metadatawidget.cpp
+++ b/src/fwk/toolkit/metadatawidget.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/toolkit/metadatawidget.cpp
  *
- * Copyright (C) 2008-2020 Hubert Figuière
+ * Copyright (C) 2008-2021 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -57,7 +57,7 @@ MetaDataWidget::MetaDataWidget(const Glib::ustring & title)
     set_sensitive(false);
 }
 
-void MetaDataWidget::set_data_format(const MetaDataSectionFormat * fmt)
+void MetaDataWidget::set_data_format(const MetaDataSectionFormat* fmt)
 {
     m_fmt = fmt;
     create_widgets_for_format(fmt);
@@ -67,11 +67,11 @@ void MetaDataWidget::rating_callback(GtkWidget* w, gint rating, gpointer user_da
 {
     auto self = static_cast<MetaDataWidget*>(user_data);
     auto id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "id"));
-    self->on_int_changed(rating, id);
+    self->on_int_changed(rating, static_cast<ffi::NiepcePropertyIdx>(id));
 }
 
 Gtk::Widget*
-MetaDataWidget::create_star_rating_widget(bool readonly, uint32_t id)
+MetaDataWidget::create_star_rating_widget(bool readonly, ffi::NiepcePropertyIdx id)
 {
     Gtk::DrawingArea* r =
         Gtk::manage(Glib::wrap(
@@ -84,7 +84,7 @@ MetaDataWidget::create_star_rating_widget(bool readonly, uint32_t id)
 }
 
 Gtk::Widget*
-MetaDataWidget::create_string_array_widget(bool readonly, uint32_t id)
+MetaDataWidget::create_string_array_widget(bool readonly, ffi::NiepcePropertyIdx id)
 {
     fwk::TokenTextView * ttv = Gtk::manage(new fwk::TokenTextView());
     if(!readonly) {
@@ -98,7 +98,7 @@ MetaDataWidget::create_string_array_widget(bool readonly, uint32_t id)
 }
 
 Gtk::Widget*
-MetaDataWidget::create_text_widget(bool readonly, uint32_t id)
+MetaDataWidget::create_text_widget(bool readonly, ffi::NiepcePropertyIdx id)
 {
     if(readonly) {
         Gtk::Label * l = Gtk::manage(new Gtk::Label());
@@ -121,7 +121,7 @@ MetaDataWidget::create_text_widget(bool readonly, uint32_t id)
 }
 
 Gtk::Widget*
-MetaDataWidget::create_string_widget(bool readonly, uint32_t id)
+MetaDataWidget::create_string_widget(bool readonly, ffi::NiepcePropertyIdx id)
 {
     if(readonly) {
         Gtk::Label * l = Gtk::manage(new Gtk::Label());
@@ -143,7 +143,7 @@ MetaDataWidget::create_string_widget(bool readonly, uint32_t id)
 }
 
 Gtk::Widget*
-MetaDataWidget::create_date_widget(bool /*readonly*/, uint32_t id)
+MetaDataWidget::create_date_widget(bool /*readonly*/, ffi::NiepcePropertyIdx id)
 {
     // for now a date widget is just like a string. Read only
     return create_string_widget(true, id);
@@ -153,10 +153,10 @@ void
 MetaDataWidget::create_widgets_for_format(const MetaDataSectionFormat * fmt)
 {
     Gtk::Widget *w = nullptr;
-    const MetaDataFormat * current = fmt->formats;
+    auto current = fmt->formats.begin();
     int n_row = 0;
 
-    while(current && current->label) {
+    while(current != fmt->formats.end()) {
         Gtk::Label *labelw = Gtk::manage(new Gtk::Label(
                                              Glib::ustring("<b>")
                                              + current->label + "</b>"));
@@ -201,7 +201,7 @@ MetaDataWidget::create_widgets_for_format(const MetaDataSectionFormat * fmt)
     m_table.show_all();
 }
 
-void MetaDataWidget::clear_widget(const std::pair<const PropertyIndex, Gtk::Widget *> & p)
+void MetaDataWidget::clear_widget(const std::pair<const ffi::NiepcePropertyIdx, Gtk::Widget *> & p)
 {
     AutoFlag flag(m_update);
     Gtk::Label * l = dynamic_cast<Gtk::Label*>(p.second);
@@ -242,7 +242,7 @@ void MetaDataWidget::set_data_source(const fwk::PropertyBagPtr& properties)
                       });
     }
     bool is_empty =
-        static_cast<bool>(properties) ? fwk_property_bag_is_empty(properties.get()) : true;
+        static_cast<bool>(properties) ? eng_property_bag_is_empty(properties.get()) : true;
     set_sensitive(!is_empty);
     if(is_empty) {
         return;
@@ -252,15 +252,15 @@ void MetaDataWidget::set_data_source(const fwk::PropertyBagPtr& properties)
         return;
     }
 
-    const MetaDataFormat * current = m_fmt->formats;
-    while(current && current->label) {
+    auto current = m_fmt->formats.begin();
+    while (current != m_fmt->formats.end()) {
         auto result = get_value_for_property(*properties, current->id);
         if (!result.empty() || !current->readonly) {
-            add_data(current, std::move(result));
+            add_data(*current, std::move(result));
         }
         else {
             DBG_OUT("get_property failed id = %d, label = %s",
-                    current->id, current->label);
+                    static_cast<uint32_t>(current->id), current->label);
         }
         current++;
     }
@@ -413,7 +413,7 @@ bool MetaDataWidget::set_date_data(Gtk::Widget* w, const PropertyValuePtr& value
     return true;
 }
 
-void MetaDataWidget::add_data(const MetaDataFormat * current,
+void MetaDataWidget::add_data(const MetaDataFormat& current,
                               fwk::Option<PropertyValuePtr>&& optional_value)
 {
     if (optional_value.empty()) {
@@ -425,7 +425,7 @@ void MetaDataWidget::add_data(const MetaDataFormat * current,
     }
 
     Gtk::Widget *w = nullptr;
-    auto iter = m_data_map.find(current->id);
+    auto iter = m_data_map.find(current.id);
     if(iter == m_data_map.end()) {
         ERR_OUT("no widget for property");
         return;
@@ -433,7 +433,7 @@ void MetaDataWidget::add_data(const MetaDataFormat * current,
 
     w = static_cast<Gtk::Label*>(iter->second);
 
-    switch(current->type) {
+    switch(current.type) {
     case MetaDT::FRAC_DEC:
         set_fraction_dec_data(w, value);
         break;
@@ -444,24 +444,24 @@ void MetaDataWidget::add_data(const MetaDataFormat * current,
         set_star_rating_data(w, value);
         break;
     case MetaDT::STRING_ARRAY:
-        set_string_array_data(w, current->readonly, value);
+        set_string_array_data(w, current.readonly, value);
         break;
     case MetaDT::TEXT:
-        set_text_data(w, current->readonly, value);
+        set_text_data(w, current.readonly, value);
         break;
     case MetaDT::DATE:
         set_date_data(w, value);
         break;
     default:
-        if (!set_string_data(w, current->readonly, value)) {
-            ERR_OUT("failed to set value for %u", current->id);
+        if (!set_string_data(w, current.readonly, value)) {
+            ERR_OUT("failed to set value for %u", static_cast<uint32_t>(current.id));
         }
         break;
     }
 }
 
 bool MetaDataWidget::on_str_changed(GdkEventFocus*, Gtk::Entry *e,
-                                    fwk::PropertyIndex prop)
+                                    ffi::NiepcePropertyIdx prop)
 {
     if(m_update) {
         return true;
@@ -472,7 +472,7 @@ bool MetaDataWidget::on_str_changed(GdkEventFocus*, Gtk::Entry *e,
 
 bool MetaDataWidget::on_text_changed(GdkEventFocus*,
                                      Glib::RefPtr<Gtk::TextBuffer> b,
-                                     fwk::PropertyIndex prop)
+                                     ffi::NiepcePropertyIdx prop)
 {
     if(m_update) {
         return true;
@@ -484,7 +484,7 @@ bool MetaDataWidget::on_text_changed(GdkEventFocus*,
 
 bool MetaDataWidget::on_string_array_changed(GdkEventFocus*,
                                              fwk::TokenTextView * ttv,
-                                             fwk::PropertyIndex prop)
+                                             ffi::NiepcePropertyIdx prop)
 {
     if(m_update) {
         return true;
@@ -496,7 +496,7 @@ bool MetaDataWidget::on_string_array_changed(GdkEventFocus*,
     return true;
 }
 
-void MetaDataWidget::on_int_changed(int value, fwk::PropertyIndex prop)
+void MetaDataWidget::on_int_changed(int value, ffi::NiepcePropertyIdx prop)
 {
     if(m_update) {
         return;
@@ -504,7 +504,7 @@ void MetaDataWidget::on_int_changed(int value, fwk::PropertyIndex prop)
     emit_metadata_changed(prop, fwk::property_value_new(value));
 }
 
-void MetaDataWidget::emit_metadata_changed(fwk::PropertyIndex prop,
+void MetaDataWidget::emit_metadata_changed(ffi::NiepcePropertyIdx prop,
                                            const fwk::PropertyValuePtr & value)
 {
     fwk::PropertyBagPtr props = fwk::property_bag_new();
diff --git a/src/fwk/toolkit/metadatawidget.hpp b/src/fwk/toolkit/metadatawidget.hpp
index 9222492..7e7f8a1 100644
--- a/src/fwk/toolkit/metadatawidget.hpp
+++ b/src/fwk/toolkit/metadatawidget.hpp
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/toolkit/metadatawidget.h
  *
- * Copyright (C) 2008-2012 Hubert Figuiere
+ * Copyright (C) 2008-2021 Hubert Figuiere
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -50,14 +50,14 @@ enum class MetaDT {
 
 struct MetaDataFormat {
     const char * label;
-    uint32_t     id;
+    ffi::NiepcePropertyIdx id;
     MetaDT       type;
     bool         readonly;
 };
 
 struct MetaDataSectionFormat {
     const char * section;
-    const MetaDataFormat * formats;
+    const std::vector<MetaDataFormat> formats;
 };
 
 class XmpMeta;
@@ -69,28 +69,28 @@ class MetaDataWidget
 public:
     MetaDataWidget(const Glib::ustring & title);
 
-    void add_data(const MetaDataFormat * current,
+    void add_data(const MetaDataFormat& current,
                   fwk::Option<PropertyValuePtr>&& value);
-    void set_data_format(const MetaDataSectionFormat * fmt);
+    void set_data_format(const MetaDataSectionFormat* fmt);
     void set_data_source(const fwk::PropertyBagPtr& properties);
 
     sigc::signal<void, const fwk::PropertyBagPtr &, const fwk::PropertyBagPtr &> signal_metadata_changed;
 protected:
-    bool on_str_changed(GdkEventFocus*, Gtk::Entry *, fwk::PropertyIndex prop);
-    bool on_text_changed(GdkEventFocus*, Glib::RefPtr<Gtk::TextBuffer> b, fwk::PropertyIndex prop);
+    bool on_str_changed(GdkEventFocus*, Gtk::Entry *, ffi::NiepcePropertyIdx prop);
+    bool on_text_changed(GdkEventFocus*, Glib::RefPtr<Gtk::TextBuffer> b, ffi::NiepcePropertyIdx prop);
     bool on_string_array_changed(GdkEventFocus*, fwk::TokenTextView * ttv,
-                                 fwk::PropertyIndex prop);
-    void on_int_changed(int, fwk::PropertyIndex prop);
+                                 ffi::NiepcePropertyIdx prop);
+    void on_int_changed(int, ffi::NiepcePropertyIdx prop);
 private:
-    void clear_widget(const std::pair<const PropertyIndex, Gtk::Widget *> & p);
+    void clear_widget(const std::pair<const ffi::NiepcePropertyIdx, Gtk::Widget *> & p);
     void create_widgets_for_format(const MetaDataSectionFormat * fmt);
 
     // the widget factory
-    Gtk::Widget* create_star_rating_widget(bool readonly, uint32_t id);
-    Gtk::Widget* create_string_array_widget(bool readonly, uint32_t id);
-    Gtk::Widget* create_text_widget(bool readonly, uint32_t id);
-    Gtk::Widget* create_string_widget(bool readonly, uint32_t id);
-    Gtk::Widget* create_date_widget(bool readonly, uint32_t id);
+    Gtk::Widget* create_star_rating_widget(bool readonly, ffi::NiepcePropertyIdx id);
+    Gtk::Widget* create_string_array_widget(bool readonly, ffi::NiepcePropertyIdx id);
+    Gtk::Widget* create_text_widget(bool readonly, ffi::NiepcePropertyIdx id);
+    Gtk::Widget* create_string_widget(bool readonly, ffi::NiepcePropertyIdx id);
+    Gtk::Widget* create_date_widget(bool readonly, ffi::NiepcePropertyIdx id);
 
     // set data
     // Fraction as a decimal
@@ -105,10 +105,10 @@ private:
                          const PropertyValuePtr& value);
     bool set_date_data(Gtk::Widget* w, const PropertyValuePtr& value);
 
-    void emit_metadata_changed(fwk::PropertyIndex prop, const fwk::PropertyValuePtr & value);
+    void emit_metadata_changed(ffi::NiepcePropertyIdx prop, const fwk::PropertyValuePtr & value);
 
     Gtk::Grid    m_table;
-    std::map<const PropertyIndex, Gtk::Widget *> m_data_map;
+    std::map<ffi::NiepcePropertyIdx, Gtk::Widget *> m_data_map;
     fwk::PropertyBagPtr m_current_data;
     const MetaDataSectionFormat * m_fmt;
     bool m_update;
diff --git a/src/niepce/modules/map/mapmodule.cpp b/src/niepce/modules/map/mapmodule.cpp
index 22d2f58..f62d7fd 100644
--- a/src/niepce/modules/map/mapmodule.cpp
+++ b/src/niepce/modules/map/mapmodule.cpp
@@ -79,13 +79,13 @@ MapModule::on_lib_notification(const eng::LibNotification &ln)
 
         if (lm) {
             fwk::PropertySetPtr propset = fwk::property_set_new();
-            ffi::fwk_property_set_add(propset.get(), eng::NpExifGpsLongProp);
-            ffi::fwk_property_set_add(propset.get(), eng::NpExifGpsLatProp);
+            ffi::eng_property_set_add(propset.get(), ffi::NiepcePropertyIdx::NpExifGpsLongProp);
+            ffi::eng_property_set_add(propset.get(), ffi::NiepcePropertyIdx::NpExifGpsLatProp);
 
             fwk::PropertyBagPtr properties = eng::libmetadata_to_properties(lm, *propset);
             double latitude, longitude;
             latitude = longitude = NAN;
-            auto result = fwk::get_value_for_property(*properties, eng::NpExifGpsLongProp);
+            auto result = fwk::get_value_for_property(*properties, 
ffi::NiepcePropertyIdx::NpExifGpsLongProp);
             if (!result.empty()) {
                 fwk::PropertyValuePtr val = result.unwrap();
                 // it is a string
@@ -94,7 +94,7 @@ MapModule::on_lib_notification(const eng::LibNotification &ln)
                         fwk::property_value_get_string(*val).c_str());
                 }
             }
-            result = fwk::get_value_for_property(*properties, eng::NpExifGpsLatProp);
+            result = fwk::get_value_for_property(*properties, ffi::NiepcePropertyIdx::NpExifGpsLatProp);
             if (!result.empty()) {
                 fwk::PropertyValuePtr val = result.unwrap();
                 // it is a string
diff --git a/src/niepce/ui/metadatapanecontroller.cpp b/src/niepce/ui/metadatapanecontroller.cpp
index a3aa3e0..088d8a2 100644
--- a/src/niepce/ui/metadatapanecontroller.cpp
+++ b/src/niepce/ui/metadatapanecontroller.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - niepce/ui/metadatapanecontroller.cpp
  *
- * Copyright (C) 2008-2018 Hubert Figuiere
+ * Copyright (C) 2008-2021 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -17,6 +17,8 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <vector>
+
 #include <glibmm/i18n.h>
 #include <gtkmm/label.h>
 #include <gtkmm/entry.h>
@@ -29,63 +31,55 @@
 
 namespace ui {
 
-const fwk::MetaDataSectionFormat *
+using ffi::NiepcePropertyIdx;
+
+const std::vector<fwk::MetaDataSectionFormat>&
 MetaDataPaneController::get_format()
 {
-    static const fwk::MetaDataFormat s_fileinfo_format[] = {
-        { _("File Name:"), eng::NpFileNameProp, fwk::MetaDT::STRING, true },
-        { _("Folder:"), eng::NpFolderProp, fwk::MetaDT::STRING, true },
-        { _("File Type:"), eng::NpFileTypeProp, fwk::MetaDT::STRING, true },
-        { _("File Size:"), eng::NpFileSizeProp, fwk::MetaDT::SIZE, true },
-        { _("Sidecar Files:"), eng::NpSidecarsProp, fwk::MetaDT::STRING_ARRAY, true },
-        { nullptr, 0, fwk::MetaDT::NONE, true }
-    };
-    static const fwk::MetaDataFormat s_camerainfo_format[] = {
-        { _("Make:"), eng::NpTiffMakeProp, fwk::MetaDT::STRING, true },
-        { _("Model:"), eng::NpTiffModelProp, fwk::MetaDT::STRING, true },
-        { _("Lens:"), eng::NpExifAuxLensProp, fwk::MetaDT::STRING, true },
-        { nullptr, 0, fwk::MetaDT::NONE, true }
-    };
-    static const fwk::MetaDataFormat s_shootinginfo_format[] = {
-        { _("Exposure Program:"), eng::NpExifExposureProgramProp, fwk::MetaDT::STRING, true },
-        { _("Speed:"), eng::NpExifExposureTimeProp, fwk::MetaDT::FRAC, true },
-        { _("Aperture:"), eng::NpExifFNumberPropProp, fwk::MetaDT::FRAC_DEC, true },
-        { _("ISO:"), eng::NpExifIsoSpeedRatingsProp, fwk::MetaDT::STRING, true },
-        { _("Exposure Bias:"), eng::NpExifExposureBiasProp, fwk::MetaDT::FRAC_DEC, true },
-        { _("Flash:"), eng::NpExifFlashFiredProp, fwk::MetaDT::STRING, true },
-        { _("Flash compensation:"), eng::NpExifAuxFlashCompensationProp, fwk::MetaDT::STRING, true },
-        { _("Focal length:"), eng::NpExifFocalLengthProp, fwk::MetaDT::FRAC_DEC, true },
-        { _("White balance:"), eng::NpExifWbProp, fwk::MetaDT::STRING, true },
-        { _("Date:"), eng::NpExifDateTimeOriginalProp, fwk::MetaDT::DATE, false },
-        { nullptr, 0, fwk::MetaDT::NONE, true }
-    };
-    static const fwk::MetaDataFormat s_iptc_format[] = {
-        { _("Headline:"), eng::NpIptcHeadlineProp, fwk::MetaDT::STRING, false },
-        { _("Caption:"), eng::NpIptcDescriptionProp, fwk::MetaDT::TEXT, false },
-        { _("Rating:"), eng::NpXmpRatingProp, fwk::MetaDT::STAR_RATING, false },
-        // FIXME change this type to the right one when there is a widget
-        { _("Label:"), eng::NpXmpLabelProp, fwk::MetaDT::STRING, true },
-        { _("Keywords:"), eng::NpIptcKeywordsProp, fwk::MetaDT::STRING_ARRAY, false },
-        { nullptr, 0, fwk::MetaDT::NONE, true }
-    };
-    static const fwk::MetaDataSectionFormat s_format[] = {
+    static const std::vector<fwk::MetaDataSectionFormat> s_format = {
         { _("File Information"),
-          s_fileinfo_format
+          {
+              { _("File Name:"), NiepcePropertyIdx::NpFileNameProp, fwk::MetaDT::STRING, true },
+              { _("Folder:"), NiepcePropertyIdx::NpFolderProp, fwk::MetaDT::STRING, true },
+              { _("File Type:"), NiepcePropertyIdx::NpFileTypeProp, fwk::MetaDT::STRING, true },
+              { _("File Size:"), NiepcePropertyIdx::NpFileSizeProp, fwk::MetaDT::SIZE, true },
+              { _("Sidecar Files:"), NiepcePropertyIdx::NpSidecarsProp, fwk::MetaDT::STRING_ARRAY, true },
+          }
         },
         { _("Camera Information"),
-          s_camerainfo_format
+          {
+              { _("Make:"), NiepcePropertyIdx::NpTiffMakeProp, fwk::MetaDT::STRING, true },
+              { _("Model:"), NiepcePropertyIdx::NpTiffModelProp, fwk::MetaDT::STRING, true },
+              { _("Lens:"), NiepcePropertyIdx::NpExifAuxLensProp, fwk::MetaDT::STRING, true },
+          }
         },
         { _("Shooting Information"),
-          s_shootinginfo_format
+          {
+              { _("Exposure Program:"), NiepcePropertyIdx::NpExifExposureProgramProp, fwk::MetaDT::STRING, 
true },
+              { _("Speed:"), NiepcePropertyIdx::NpExifExposureTimeProp, fwk::MetaDT::FRAC, true },
+              { _("Aperture:"), NiepcePropertyIdx::NpExifFNumberPropProp, fwk::MetaDT::FRAC_DEC, true },
+              { _("ISO:"), NiepcePropertyIdx::NpExifIsoSpeedRatingsProp, fwk::MetaDT::STRING, true },
+              { _("Exposure Bias:"), NiepcePropertyIdx::NpExifExposureBiasProp, fwk::MetaDT::FRAC_DEC, true 
},
+              { _("Flash:"), NiepcePropertyIdx::NpExifFlashFiredProp, fwk::MetaDT::STRING, true },
+              { _("Flash compensation:"), NiepcePropertyIdx::NpExifAuxFlashCompensationProp, 
fwk::MetaDT::STRING, true },
+              { _("Focal length:"), NiepcePropertyIdx::NpExifFocalLengthProp, fwk::MetaDT::FRAC_DEC, true },
+              { _("White balance:"), NiepcePropertyIdx::NpExifWbProp, fwk::MetaDT::STRING, true },
+              { _("Date:"), NiepcePropertyIdx::NpExifDateTimeOriginalProp, fwk::MetaDT::DATE, false },
+          }
         },
         { _("IPTC"),
-          s_iptc_format
+          {
+              { _("Headline:"), NiepcePropertyIdx::NpIptcHeadlineProp, fwk::MetaDT::STRING, false },
+              { _("Caption:"), NiepcePropertyIdx::NpIptcDescriptionProp, fwk::MetaDT::TEXT, false },
+              { _("Rating:"), NiepcePropertyIdx::NpXmpRatingProp, fwk::MetaDT::STAR_RATING, false },
+              // FIXME change this type to the right one when there is a widget
+              { _("Label:"), NiepcePropertyIdx::NpXmpLabelProp, fwk::MetaDT::STRING, true },
+              { _("Keywords:"), NiepcePropertyIdx::NpIptcKeywordsProp, fwk::MetaDT::STRING_ARRAY, false },
+          }
         },
         { _("Rights"),
-          nullptr
+          std::vector<fwk::MetaDataFormat>()
         },
-        { nullptr, nullptr
-        }
     };
     return s_format;
 }
@@ -94,14 +88,14 @@ const fwk::PropertySet* MetaDataPaneController::get_property_set()
 {
     static fwk::PropertySet* propset = nullptr;
     if(!propset) {
-        propset = ffi::fwk_property_set_new();
-        const fwk::MetaDataSectionFormat * formats = get_format();
-
-        const fwk::MetaDataSectionFormat * current = formats;
-        while(current->section) {
-            const fwk::MetaDataFormat * format = current->formats;
-            while(format && format->label) {
-                ffi::fwk_property_set_add(propset, format->id);
+        propset = ffi::eng_property_set_new();
+        const std::vector<fwk::MetaDataSectionFormat>& formats = get_format();
+
+        auto current = formats.begin();
+        while (current != formats.end()) {
+            auto format = current->formats.begin();
+            while (format != current->formats.end()) {
+                ffi::eng_property_set_add(propset, format->id);
                 format++;
             }
             current++;
@@ -131,13 +125,13 @@ MetaDataPaneController::buildWidget()
     m_widget = box;
     DBG_ASSERT(box, "dockable vbox not found");
 
-    auto formats = get_format();
+    const auto& formats = get_format();
 
-    auto current = formats;
-    while(current->section) {
+    auto current = formats.begin();
+    while (current != formats.end()) {
         auto w = Gtk::manage(new fwk::MetaDataWidget(current->section));
         box->pack_start(*w, Gtk::PACK_SHRINK, 0);
-        w->set_data_format(current);
+        w->set_data_format(&*current);
         m_widgets.push_back(w);
         w->signal_metadata_changed.connect(
             sigc::mem_fun(*this,
diff --git a/src/niepce/ui/metadatapanecontroller.hpp b/src/niepce/ui/metadatapanecontroller.hpp
index 613b470..9ff7de6 100644
--- a/src/niepce/ui/metadatapanecontroller.hpp
+++ b/src/niepce/ui/metadatapanecontroller.hpp
@@ -54,7 +54,7 @@ private:
 
     std::vector<fwk::MetaDataWidget *> m_widgets;
 
-    static const fwk::MetaDataSectionFormat * get_format();
+    static const std::vector<fwk::MetaDataSectionFormat>& get_format();
     static const fwk::PropertySet* get_property_set();
 
     eng::library_id_t m_fileid;
diff --git a/src/niepce/ui/selectioncontroller.cpp b/src/niepce/ui/selectioncontroller.cpp
index 3624aa9..0c641b3 100644
--- a/src/niepce/ui/selectioncontroller.cpp
+++ b/src/niepce/ui/selectioncontroller.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - niepce/ui/selectioncontroller.cpp
  *
- * Copyright (C) 2008-2020 Hubert Figuière
+ * Copyright (C) 2008-2021 Hubert Figuière
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -184,7 +184,7 @@ void SelectionController::rotate(int angle)
 
 bool SelectionController::_set_metadata(const std::string & undo_label,
                                         eng::library_id_t file_id,
-                                        ffi::Np meta,
+                                        ffi::NiepcePropertyIdx meta,
                                         int old_value, int new_value)
 {
     std::shared_ptr<fwk::UndoTransaction> undo =
@@ -210,9 +210,9 @@ bool SelectionController::_set_metadata(const std::string & undo_label,
                                         const fwk::PropertyBagPtr & old)
 {
     auto undo = fwk::Application::app()->begin_undo(undo_label);
-    auto len = fwk_property_bag_len(props.get());
+    auto len = eng_property_bag_len(props.get());
     for (size_t i = 0; i < len; i++) {
-        auto key = fwk_property_bag_key_by_index(props.get(), i);
+        auto key = eng_property_bag_key_by_index(props.get(), i);
         fwk::PropertyValuePtr value = fwk::property_bag_value(old, key);
         /*
         if (!result.empty()) {
@@ -230,11 +230,11 @@ bool SelectionController::_set_metadata(const std::string & undo_label,
         undo->new_command<void>(
             [libclient, file_id, key, new_value] () {
                 ffi::libraryclient_set_metadata(
-                    libclient->client(), file_id, static_cast<ffi::Np>(key), new_value.get());
+                    libclient->client(), file_id, static_cast<ffi::NiepcePropertyIdx>(key), new_value.get());
             },
             [libclient, file_id, key, value] () {
                 ffi::libraryclient_set_metadata(
-                    libclient->client(), file_id, static_cast<ffi::Np>(key), value.get());
+                    libclient->client(), file_id, static_cast<ffi::NiepcePropertyIdx>(key), value.get());
             });
     }
     undo->execute();
@@ -243,23 +243,23 @@ bool SelectionController::_set_metadata(const std::string & undo_label,
 
 void SelectionController::set_label(int label)
 {
-    set_property(eng::NpXmpLabelProp, label);
+    set_property(ffi::NiepcePropertyIdx::NpXmpLabelProp, label);
 }
 
 
 void SelectionController::set_rating(int rating)
 {
-    set_property(eng::NpXmpRatingProp, rating);
+    set_property(ffi::NiepcePropertyIdx::NpXmpRatingProp, rating);
 }
 
 void SelectionController::set_flag(int flag)
 {
-    set_property(eng::NpNiepceFlagProp, flag);
+    set_property(ffi::NiepcePropertyIdx::NpNiepceFlagProp, flag);
 }
 
-void SelectionController::set_property(ffi::Np idx, int value)
+void SelectionController::set_property(ffi::NiepcePropertyIdx idx, int value)
 {
-    DBG_OUT("property %u = %d", idx, value);
+    DBG_OUT("property %u = %d", static_cast<uint32_t>(idx), value);
     eng::library_id_t selection = get_selection();
     if(selection >= 0) {
         eng::LibFilePtr file = m_imageliststore->get_file(selection);
@@ -271,13 +271,13 @@ void SelectionController::set_property(ffi::Np idx, int value)
         int32_t old_value = engine_db_libfile_property(file.get(), idx);
         const char *action = nullptr;
         switch(idx) {
-        case eng::NpNiepceFlagProp:
+        case ffi::NiepcePropertyIdx::NpNiepceFlagProp:
             action = _("Set Flag");
             break;
-        case eng::NpXmpRatingProp:
+        case ffi::NiepcePropertyIdx::NpXmpRatingProp:
             action = _("Set Rating");
             break;
-        case eng::NpXmpLabelProp:
+        case ffi::NiepcePropertyIdx::NpXmpLabelProp:
             action = _("Set Label");
             break;
         default:
diff --git a/src/niepce/ui/selectioncontroller.hpp b/src/niepce/ui/selectioncontroller.hpp
index 09ee4da..0a105fe 100644
--- a/src/niepce/ui/selectioncontroller.hpp
+++ b/src/niepce/ui/selectioncontroller.hpp
@@ -95,7 +95,7 @@ public:
     /** set flag */
     void set_flag(int flag);
 
-    void set_property(ffi::Np idx, int value);
+    void set_property(ffi::NiepcePropertyIdx idx, int value);
 
     void set_properties(const fwk::PropertyBagPtr & props,
                         const fwk::PropertyBagPtr & old);
@@ -118,7 +118,7 @@ private:
 
     bool _set_metadata(const std::string & undo_label,
                        eng::library_id_t file_id,
-                       ffi::Np meta,
+                       ffi::NiepcePropertyIdx meta,
                        int old_value, int new_value);
     bool _set_metadata(const std::string & undo_label,
                        eng::library_id_t file_id,
diff --git a/src/rust_bindings.hpp b/src/rust_bindings.hpp
index ff71734..571a005 100644
--- a/src/rust_bindings.hpp
+++ b/src/rust_bindings.hpp
@@ -1,7 +1,7 @@
 /*
  * niepce - rust_bindings.hpp
  *
- * Copyright (C) 2017-2018 Hubert Figuiere
+ * Copyright (C) 2017-2021 Hubert Figuiere
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -21,15 +21,14 @@
 
 #include <gtk/gtk.h>
 
-#include "engine/db/properties-enum.hpp"
-
 namespace ffi {
 class rust_str;
 struct Utc;
 template <class T>
 struct DateTime;
 typedef rust_str str;
-typedef eng::NiepceProperties Np;
+struct NiepcePropertyBag;
+struct NiepcePropertySet;
 }
 
 #include "target/fwk_bindings.h"
@@ -40,14 +39,16 @@ namespace fwk {
 
 typedef ffi::ExempiManager ExempiManager;
 typedef ffi::PropertyValue PropertyValue;
-typedef ffi::PropertyBag PropertyBag;
-typedef ffi::PropertySet PropertySet;
+typedef ffi::NiepcePropertyBag PropertyBag;
+typedef ffi::NiepcePropertySet PropertySet;
 typedef ffi::Date Date;
 typedef ffi::RgbColour RgbColour;
 typedef ffi::FileList FileList;
 }
 
 namespace eng {
+typedef ffi::NiepcePropertyIdx Np;
+using NiepcePropertyIdx = ffi::NiepcePropertyIdx;
 typedef ffi::LibraryId library_id_t; // XXX change this to LibraryId
 typedef ffi::FileType FileType;
 typedef ffi::FileStatus FileStatus;


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