[niepce] rust: Port MetadataWidget to Rust
- From: Hubert Figuière <hub src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [niepce] rust: Port MetadataWidget to Rust
- Date: Sun, 16 Oct 2022 22:52:06 +0000 (UTC)
commit 6cc1b30d772f05dbf1f638a2141f54797b3bf26c
Author: Hubert Figuière <hub figuiere net>
Date: Sun Oct 16 17:58:57 2022 -0400
rust: Port MetadataWidget to Rust
- Added metadata_widget.rs
- Improved RatingLabel API
- Added cxx binding in niepce-main
- Deleted metadatawidget.* notabtextview.* and tokentextview.*
- Metadata formats are defined in Rust
- Remove cbindgen from npc-fwk
.gitignore | 4 +
Cargo.lock | 2 +-
crates/npc-engine/build.rs | 1 +
crates/npc-engine/src/db/libmetadata.rs | 24 +
crates/npc-engine/src/lib.rs | 57 ++-
crates/npc-fwk/Cargo.toml | 5 -
crates/npc-fwk/build.rs | 38 --
crates/npc-fwk/src/base/fractions.rs | 28 +-
crates/npc-fwk/src/base/propertybag.rs | 5 +
crates/npc-fwk/src/base/propertyvalue.rs | 40 +-
crates/npc-fwk/src/lib.rs | 40 +-
crates/npc-fwk/src/toolkit/widgets.rs | 6 +
.../npc-fwk/src/toolkit/widgets/metadata_widget.rs | 539 +++++++++++++++++++++
crates/npc-fwk/src/toolkit/widgets/rating_label.rs | 50 +-
.../npc-fwk/src/toolkit/widgets/token_text_view.rs | 7 +-
crates/npc-fwk/src/toolkit/widgets/toolbox_item.rs | 4 +
niepce-main/Cargo.toml | 11 +-
niepce-main/src/lib.rs | 25 +-
niepce-main/src/niepce/ui.rs | 3 +-
.../src/niepce/ui/metadata_pane_controller.rs | 61 +++
src/Makefile.am | 2 +-
src/engine/db/libmetadata.cpp | 8 +-
src/engine/db/libmetadata.hpp | 4 +-
src/fwk/Makefile.am | 23 +-
src/fwk/base/propertybag.cpp | 9 +-
src/fwk/base/propertybag.hpp | 7 +-
src/fwk/cxx_prelude.hpp | 12 +
src/fwk/toolkit/Makefile.am | 5 +-
src/fwk/toolkit/metadatawidget.cpp | 527 --------------------
src/fwk/toolkit/metadatawidget.hpp | 129 -----
src/fwk/toolkit/widgets/notabtextview.cpp | 40 --
src/fwk/toolkit/widgets/notabtextview.hpp | 46 --
src/fwk/toolkit/widgets/tokentextview.cpp | 60 ---
src/fwk/toolkit/widgets/tokentextview.hpp | 52 --
src/fwk/utils/init.cpp | 2 +-
src/niepce/ui/gridviewmodule.cpp | 4 +-
src/niepce/ui/gridviewmodule.hpp | 3 +-
src/niepce/ui/metadatapanecontroller.cpp | 116 ++---
src/niepce/ui/metadatapanecontroller.hpp | 18 +-
src/niepce/ui/selectioncontroller.cpp | 18 +-
src/niepce/ui/selectioncontroller.hpp | 8 +-
src/rust_bindings.hpp | 3 +-
42 files changed, 970 insertions(+), 1076 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 44aace74..0e3f8e6a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -97,6 +97,10 @@ m4/xsize.m4
/src/fwk/cxx_fwk_bindings.hpp
/src/fwk/cxx_eng_bindings.cpp
/src/fwk/cxx_eng_bindings.hpp
+/src/fwk/cxx_widgets_bindings.cpp
+/src/fwk/cxx_widgets_bindings.hpp
+/src/fwk/cxx_npc_bindings.cpp
+/src/fwk/cxx_npc_bindings.hpp
/src/libraryclient/test_worker
/src/engine/test_library
/src/engine/test_filebundle
diff --git a/Cargo.lock b/Cargo.lock
index 7d6be421..6ba724a8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -749,6 +749,7 @@ dependencies = [
"async-channel",
"cairo-rs",
"cbindgen",
+ "cxx",
"gdk-pixbuf",
"gdk-pixbuf-sys",
"gdk4",
@@ -791,7 +792,6 @@ version = "0.1.0"
dependencies = [
"async-channel",
"cairo-rs",
- "cbindgen",
"chrono",
"cxx",
"exempi",
diff --git a/crates/npc-engine/build.rs b/crates/npc-engine/build.rs
index 98867eda..24690538 100644
--- a/crates/npc-engine/build.rs
+++ b/crates/npc-engine/build.rs
@@ -39,6 +39,7 @@ fn main() {
.exclude_item("NiepcePropertyBag")
.exclude_item("PropertySet")
.exclude_item("PropertyBag")
+ .exclude_item("WrappedPropertyBag")
.exclude_item("Option")
.with_crate(&crate_dir)
.generate()
diff --git a/crates/npc-engine/src/db/libmetadata.rs b/crates/npc-engine/src/db/libmetadata.rs
index 38642e9a..f6bd50aa 100644
--- a/crates/npc-engine/src/db/libmetadata.rs
+++ b/crates/npc-engine/src/db/libmetadata.rs
@@ -304,3 +304,27 @@ pub extern "C" fn engine_libmetadata_to_properties(
let result = Box::new(meta.to_properties(propset));
Box::into_raw(result)
}
+
+use npc_fwk::toolkit::widgets::WrappedPropertyBag;
+
+fn into_u32(from: NiepcePropertyBag) -> PropertyBag<u32> {
+ PropertyBag {
+ bag: from.bag.iter().map(|v| (*v).into()).collect(),
+ map: from
+ .map
+ .iter()
+ .map(|(k, v)| ((*k).into(), v.clone()))
+ .collect(),
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn engine_libmetadata_to_wrapped_properties(
+ meta: &LibMetadata,
+ propset: &NiepcePropertySet,
+) -> *mut WrappedPropertyBag {
+ let bag = meta.to_properties(propset);
+ let bag = into_u32(bag);
+ let result = Box::new(WrappedPropertyBag(bag));
+ Box::into_raw(result)
+}
diff --git a/crates/npc-engine/src/lib.rs b/crates/npc-engine/src/lib.rs
index 7cbad7ec..671f4971 100644
--- a/crates/npc-engine/src/lib.rs
+++ b/crates/npc-engine/src/lib.rs
@@ -49,11 +49,6 @@ pub extern "C" fn eng_property_set_add(set: &mut NiepcePropertySet, v: NiepcePro
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
@@ -104,6 +99,58 @@ pub extern "C" fn eng_property_bag_set_value(
b.set_value(key.into(), v.clone())
}
+use npc_fwk::toolkit::widgets::WrappedPropertyBag;
+
+/// Delete the %WrappedPropertyBag object
+///
+/// # Safety
+/// Dereference the raw pointer.
+#[no_mangle]
+pub unsafe extern "C" fn fwk_wrapped_property_bag_delete(bag: *mut WrappedPropertyBag) {
+ drop(Box::from_raw(bag));
+}
+
+/// Clone the %WrappedPropertyBag object. Use this to take it out of the GValue.
+///
+/// # Safety
+/// Dereference the raw pointer.
+#[no_mangle]
+pub unsafe extern "C" fn fwk_wrapped_property_bag_clone(
+ bag: *const WrappedPropertyBag,
+) -> *mut WrappedPropertyBag {
+ Box::into_raw(Box::new((*bag).clone()))
+}
+
+/// # Safety
+/// Dereference the raw pointer.
+#[no_mangle]
+pub unsafe extern "C" fn fwk_property_bag_len(bag: &WrappedPropertyBag) -> usize {
+ (*bag).0.len()
+}
+
+/// # Safety
+/// Dereference the raw pointer.
+#[no_mangle]
+pub unsafe extern "C" fn fwk_property_bag_key_by_index(
+ bag: &WrappedPropertyBag,
+ idx: usize,
+) -> u32 {
+ (*bag).0.bag[idx]
+}
+
+#[no_mangle]
+pub extern "C" fn fwk_property_bag_value(
+ b: &WrappedPropertyBag,
+ key: PropertyIndex,
+) -> *mut PropertyValue {
+ if b.0.map.contains_key(&key) {
+ let value = Box::new(b.0.map[&key].clone());
+ Box::into_raw(value)
+ } else {
+ ptr::null_mut()
+ }
+}
+
use crate::db::{Keyword, Label, LibFile, LibMetadata};
#[cxx::bridge(namespace = "eng")]
diff --git a/crates/npc-fwk/Cargo.toml b/crates/npc-fwk/Cargo.toml
index 4766c377..471fcbc6 100644
--- a/crates/npc-fwk/Cargo.toml
+++ b/crates/npc-fwk/Cargo.toml
@@ -3,7 +3,6 @@ name = "npc-fwk"
version = "0.1.0"
authors = ["Hubert Figuière <hub figuiere net>"]
edition = "2018"
-build = "build.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -30,7 +29,3 @@ multimap = "0.4.0"
once_cell = "^1.12.0"
rexiv2 = "^0.9.1"
tempfile = "3.3.0"
-
-
-[build-dependencies]
-cbindgen = { version = "0.20.0" }
diff --git a/crates/npc-fwk/src/base/fractions.rs b/crates/npc-fwk/src/base/fractions.rs
index a6c692b8..a7d08c58 100644
--- a/crates/npc-fwk/src/base/fractions.rs
+++ b/crates/npc-fwk/src/base/fractions.rs
@@ -1,7 +1,7 @@
/*
* niepce - fwk/base/fractions.rs
*
- * Copyright (C) 2017 Hubert Figuière
+ * Copyright (C) 2017-2022 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
@@ -19,7 +19,7 @@
use std::f64;
-pub fn fraction_to_decimal(value: &str) -> Option<f64> {
+pub fn parse_fraction(value: &str) -> Option<(i64, i64)> {
let numbers: Vec<i64> = value
.split('/')
.map(|s| s.parse::<i64>().unwrap_or(0))
@@ -30,13 +30,33 @@ pub fn fraction_to_decimal(value: &str) -> Option<f64> {
if numbers[1] == 0 {
return None;
}
- Some(numbers[0] as f64 / numbers[1] as f64)
+ Some((numbers[0], numbers[1]))
+}
+
+pub fn fraction_to_decimal(value: &str) -> Option<f64> {
+ parse_fraction(value).map(|(n, d)| n as f64 / d as f64)
}
#[cfg(test)]
mod tests {
#[test]
- fn faction_to_decimal_works() {
+ fn parse_fraction_works() {
+ let f = super::parse_fraction("1/4");
+ assert!(f.is_some());
+ assert_eq!(f.unwrap(), (1, 4));
+
+ let f = super::parse_fraction("foobar");
+ assert!(f.is_none());
+
+ let f = super::parse_fraction("1/0");
+ assert!(f.is_none());
+
+ let f = super::parse_fraction("1/0/1");
+ assert!(f.is_none());
+ }
+
+ #[test]
+ fn fraction_to_decimal_works() {
use super::fraction_to_decimal;
let f = fraction_to_decimal("1/4");
diff --git a/crates/npc-fwk/src/base/propertybag.rs b/crates/npc-fwk/src/base/propertybag.rs
index e5ccf925..d71e9acd 100644
--- a/crates/npc-fwk/src/base/propertybag.rs
+++ b/crates/npc-fwk/src/base/propertybag.rs
@@ -21,6 +21,7 @@ use std::collections::BTreeMap;
use crate::base::propertyvalue::PropertyValue;
+#[derive(Clone)]
pub struct PropertyBag<Index> {
pub bag: Vec<Index>,
pub map: BTreeMap<Index, PropertyValue>,
@@ -48,6 +49,10 @@ impl<Index: Ord + Copy> PropertyBag<Index> {
self.bag.len()
}
+ pub fn value(&self, key: &Index) -> Option<&PropertyValue> {
+ self.map.get(key)
+ }
+
pub fn set_value(&mut self, key: Index, value: PropertyValue) -> bool {
let ret = self.map.insert(key, value);
if ret.is_some() {
diff --git a/crates/npc-fwk/src/base/propertyvalue.rs b/crates/npc-fwk/src/base/propertyvalue.rs
index ef8151b9..c10584f3 100644
--- a/crates/npc-fwk/src/base/propertyvalue.rs
+++ b/crates/npc-fwk/src/base/propertyvalue.rs
@@ -19,7 +19,8 @@
use super::date::Date;
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, glib::Boxed)]
+#[boxed_type(name = "PropertyValue")]
pub enum PropertyValue {
Empty,
Int(i32),
@@ -47,6 +48,13 @@ impl PropertyValue {
matches!(*self, PropertyValue::String(_))
}
+ pub fn integer(&self) -> Option<i32> {
+ match *self {
+ PropertyValue::Int(i) => Some(i),
+ _ => None,
+ }
+ }
+
pub fn integer_unchecked(&self) -> i32 {
match *self {
PropertyValue::Int(i) => i,
@@ -54,6 +62,13 @@ impl PropertyValue {
}
}
+ pub fn date(&self) -> Option<&Date> {
+ match *self {
+ PropertyValue::Date(ref d) => Some(d),
+ _ => None,
+ }
+ }
+
pub fn date_unchecked(&self) -> Box<Date> {
match *self {
PropertyValue::Date(ref d) => Box::new(*d),
@@ -61,6 +76,13 @@ impl PropertyValue {
}
}
+ pub fn string(&self) -> Option<&str> {
+ match *self {
+ PropertyValue::String(ref s) => Some(s),
+ _ => None,
+ }
+ }
+
pub fn string_unchecked(&self) -> &str {
match *self {
PropertyValue::String(ref s) => s,
@@ -80,6 +102,13 @@ impl PropertyValue {
}
}
+ pub fn string_array(&self) -> Option<&[String]> {
+ match *self {
+ PropertyValue::StringArray(ref sa) => Some(sa),
+ _ => None,
+ }
+ }
+
pub fn string_array_unchecked(&self) -> &[String] {
match *self {
PropertyValue::StringArray(ref sa) => sa,
@@ -88,19 +117,10 @@ impl PropertyValue {
}
}
-/// Create a new String %PropertyValue from a string
-pub fn property_value_new_str(v: &str) -> Box<PropertyValue> {
- Box::new(PropertyValue::String(v.to_string()))
-}
-
pub fn property_value_new_int(v: i32) -> Box<PropertyValue> {
Box::new(PropertyValue::Int(v))
}
-pub fn property_value_new_date(v: &Date) -> Box<PropertyValue> {
- Box::new(PropertyValue::Date(*v))
-}
-
pub fn property_value_new_string_array() -> Box<PropertyValue> {
Box::new(PropertyValue::StringArray(vec![]))
}
diff --git a/crates/npc-fwk/src/lib.rs b/crates/npc-fwk/src/lib.rs
index 179de4ef..1fd94520 100644
--- a/crates/npc-fwk/src/lib.rs
+++ b/crates/npc-fwk/src/lib.rs
@@ -22,7 +22,7 @@ pub mod base;
pub mod toolkit;
pub mod utils;
-pub use self::base::fractions::fraction_to_decimal;
+pub use self::base::fractions::{fraction_to_decimal, parse_fraction};
pub use self::base::propertybag::PropertyBag;
pub use self::base::propertyvalue::PropertyValue;
pub use self::base::PropertySet;
@@ -52,11 +52,9 @@ use glib::translate::*;
use self::base::rgbcolour::RgbColour;
use crate::base::date::Date;
-use crate::base::propertyvalue::{
- property_value_new_date, property_value_new_int, property_value_new_str,
- property_value_new_string_array,
-};
+use crate::base::propertyvalue::{property_value_new_int, property_value_new_string_array};
use crate::toolkit::thumbnail::Thumbnail;
+use crate::toolkit::widgets::MetadataWidget;
use crate::toolkit::Configuration;
use crate::utils::files::FileList;
@@ -89,10 +87,6 @@ pub fn gps_coord_from_xmp_(value: &str) -> f64 {
gps_coord_from_xmp(value).unwrap_or(f64::NAN)
}
-pub fn fraction_to_decimal_(value: &str) -> f64 {
- fraction_to_decimal(value).unwrap_or(f64::NAN)
-}
-
pub fn thumbnail_for_file(path: &str, w: i32, h: i32, orientation: i32) -> Box<Thumbnail> {
Box::new(Thumbnail::thumbnail_file(path, w, h, orientation))
}
@@ -143,6 +137,10 @@ pub fn file_list_new() -> Box<FileList> {
Box::new(FileList::default())
}
+pub fn metadata_widget_new(title: &str) -> Box<MetadataWidget> {
+ Box::new(MetadataWidget::new(title))
+}
+
#[cxx::bridge(namespace = "fwk")]
mod ffi {
struct SharedConfiguration {
@@ -188,8 +186,6 @@ mod ffi {
extern "Rust" {
#[cxx_name = "gps_coord_from_xmp"]
fn gps_coord_from_xmp_(value: &str) -> f64;
- #[cxx_name = "fraction_to_decimal"]
- fn fraction_to_decimal_(value: &str) -> f64;
}
extern "Rust" {
@@ -230,9 +226,7 @@ mod ffi {
extern "Rust" {
type PropertyValue;
- fn property_value_new_str(v: &str) -> Box<PropertyValue>;
fn property_value_new_int(v: i32) -> Box<PropertyValue>;
- fn property_value_new_date(v: &Date) -> Box<PropertyValue>;
fn property_value_new_string_array() -> Box<PropertyValue>;
fn is_empty(&self) -> bool;
@@ -250,4 +244,24 @@ mod ffi {
#[cxx_name = "get_string_array"]
fn string_array_unchecked(&self) -> &[String];
}
+
+ extern "C++" {
+ include!("fwk/cxx_widgets_bindings.hpp");
+
+ type WrappedPropertyBag = crate::toolkit::widgets::WrappedPropertyBag;
+ type MetadataSectionFormat = crate::toolkit::widgets::MetadataSectionFormat;
+ }
+
+ extern "Rust" {
+ type MetadataWidget;
+
+ fn gobj(&self) -> *mut c_char;
+ #[cxx_name = "MetadataWidget_new"]
+ fn metadata_widget_new(title: &str) -> Box<MetadataWidget>;
+ #[cxx_name = "set_data_format"]
+ fn set_data_format_(&self, fmt: &MetadataSectionFormat);
+ #[cxx_name = "set_data_source"]
+ fn set_data_source_wrapped(&self, properties: &WrappedPropertyBag);
+ fn set_data_source_none(&self);
+ }
}
diff --git a/crates/npc-fwk/src/toolkit/widgets.rs b/crates/npc-fwk/src/toolkit/widgets.rs
index c20ec9f7..bbaf466e 100644
--- a/crates/npc-fwk/src/toolkit/widgets.rs
+++ b/crates/npc-fwk/src/toolkit/widgets.rs
@@ -17,15 +17,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+mod metadata_widget;
pub mod rating_label;
mod token_text_view;
mod toolbox_item;
// Re-exports
+pub use metadata_widget::{
+ MetaDT, MetadataFormat, MetadataSectionFormat, MetadataWidget, WrappedPropertyBag,
+};
+pub use rating_label::RatingLabel;
pub use token_text_view::TokenTextView;
pub use toolbox_item::ToolboxItem;
pub mod prelude {
+ pub use super::rating_label::RatingLabelExt;
pub use super::toolbox_item::ToolboxItemExt;
pub use super::toolbox_item::ToolboxItemImpl;
}
diff --git a/crates/npc-fwk/src/toolkit/widgets/metadata_widget.rs
b/crates/npc-fwk/src/toolkit/widgets/metadata_widget.rs
new file mode 100644
index 00000000..5fe059ab
--- /dev/null
+++ b/crates/npc-fwk/src/toolkit/widgets/metadata_widget.rs
@@ -0,0 +1,539 @@
+/*
+ * niepce - fwk/toolkit/widgets/metadata_widget.rs
+ *
+ * Copyright (C) 2022 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use std::ffi::c_char;
+
+use glib::translate::*;
+use glib::Cast;
+use gtk4::subclass::prelude::*;
+
+use super::ToolboxItem;
+use crate::PropertyBag;
+
+/// A wrapped PropertyBag to use in the cxx bridge.
+#[derive(Clone, Default, glib::Boxed)]
+#[boxed_type(name = "PropertyBag")]
+pub struct WrappedPropertyBag(pub PropertyBag<u32>);
+
+impl std::ops::Deref for WrappedPropertyBag {
+ type Target = PropertyBag<u32>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl std::ops::DerefMut for WrappedPropertyBag {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+use cxx::{type_id, ExternType};
+
+unsafe impl ExternType for WrappedPropertyBag {
+ type Id = type_id!("fwk::WrappedPropertyBag");
+ type Kind = cxx::kind::Opaque;
+}
+
+#[cxx::bridge(namespace = "fwk")]
+mod ffi {
+ extern "C++" {
+ include!("fwk/cxx_prelude.hpp");
+ }
+
+ // This bridge content should be moved when the bridge is removed.
+ #[repr(u32)]
+ #[derive(Clone)]
+ enum MetaDT {
+ #[allow(dead_code)]
+ NONE = 0,
+ #[allow(dead_code)]
+ STRING,
+ STRING_ARRAY,
+ TEXT,
+ DATE,
+ FRAC,
+ FRAC_DEC, // Fraction as decimal
+ STAR_RATING,
+ #[allow(dead_code)]
+ SIZE, // Size in bytes
+ }
+
+ #[derive(Clone)]
+ struct MetadataFormat {
+ label: String,
+ id: u32, // NiepcePropertyIdx
+ type_: MetaDT,
+ readonly: bool,
+ }
+
+ #[derive(Clone)]
+ struct MetadataSectionFormat {
+ section: String,
+ formats: Vec<MetadataFormat>,
+ }
+}
+
+pub use ffi::{MetaDT, MetadataFormat, MetadataSectionFormat};
+
+glib::wrapper! {
+ pub struct MetadataWidget(
+ ObjectSubclass<imp::MetadataWidget>)
+ @extends ToolboxItem, gtk4::Box, gtk4::Widget;
+}
+
+impl MetadataWidget {
+ pub fn new(title: &str) -> MetadataWidget {
+ let obj: MetadataWidget = glib::Object::new(&[]).expect("Failed to create MetadataWidget");
+ obj.upcast_ref::<ToolboxItem>().set_title(title);
+
+ obj
+ }
+
+ // cxx
+ pub fn set_data_source_wrapped(&self, properties: &WrappedPropertyBag) {
+ self.set_data_source(Some(properties.0.clone()))
+ }
+
+ // cxx
+ pub fn set_data_source_none(&self) {
+ self.set_data_source(None)
+ }
+
+ // cxx
+ pub fn gobj(&self) -> *mut c_char {
+ let gobj: *mut gtk4_sys::GtkWidget = self.upcast_ref::<gtk4::Widget>().to_glib_none().0;
+ gobj as *mut c_char
+ }
+
+ // cxx
+ pub fn set_data_format_(&self, fmt: &MetadataSectionFormat) {
+ self.set_data_format(Some(fmt.clone()));
+ }
+}
+
+trait MetadataWidgetExt {
+ fn set_data_source(&self, properties: Option<PropertyBag<u32>>);
+ fn set_data_format(&self, fmt: Option<MetadataSectionFormat>);
+}
+
+impl MetadataWidgetExt for MetadataWidget {
+ /// Set the data source of the metadata.
+ fn set_data_source(&self, properties: Option<PropertyBag<u32>>) {
+ self.imp().set_data_source(properties);
+ }
+
+ fn set_data_format(&self, fmt: Option<MetadataSectionFormat>) {
+ self.imp().set_data_format(fmt);
+ }
+}
+
+mod imp {
+ use std::cell::RefCell;
+ use std::collections::HashMap;
+
+ use glib::subclass::*;
+ use glib::Cast;
+ use glib::StaticType;
+ use gtk4::prelude::*;
+ use gtk4::subclass::prelude::*;
+
+ use crate::{PropertyBag, PropertyValue};
+
+ use super::super::prelude::*;
+ use super::super::{RatingLabel, TokenTextView};
+ use super::{MetaDT, MetadataFormat, MetadataSectionFormat, WrappedPropertyBag};
+
+ fn clear_widget(widget: >k4::Widget) {
+ if let Some(label) = widget.downcast_ref::<gtk4::Label>() {
+ label.set_text("");
+ } else if let Some(entry) = widget.downcast_ref::<gtk4::Entry>() {
+ entry.set_text("");
+ } else if let Some(ttv) = widget.downcast_ref::<TokenTextView>() {
+ ttv.set_tokens(&[]);
+ } else if let Some(tv) = widget.downcast_ref::<gtk4::TextView>() {
+ tv.buffer().set_text("");
+ } else if let Some(rating) = widget.downcast_ref::<RatingLabel>() {
+ rating.set_rating(0);
+ } else {
+ err_out!("Unknow widget type {}", widget.type_().name());
+ }
+ }
+
+ pub struct MetadataWidget {
+ widget: gtk4::Grid,
+ data_map: RefCell<HashMap<u32, gtk4::Widget>>,
+ current_data: RefCell<Option<PropertyBag<u32>>>,
+ fmt: RefCell<Option<MetadataSectionFormat>>,
+ }
+
+ impl MetadataWidget {
+ fn create_star_rating_widget(&self, readonly: bool, id: u32) -> gtk4::Widget {
+ let rating = RatingLabel::new(0, !readonly);
+ if !readonly {
+ let obj = self.instance();
+ rating.connect_rating_changed(glib::clone!(@weak obj => move |_, rating| {
+ obj.imp().emit_metadata_changed(id, &PropertyValue::Int(rating));
+ }));
+ }
+
+ rating.upcast()
+ }
+
+ fn create_text_widget(&self, readonly: bool, id: u32) -> gtk4::Widget {
+ if readonly {
+ self.create_string_widget(readonly, id)
+ } else {
+ let entry = gtk4::TextView::new();
+ entry.set_accepts_tab(false);
+ entry.set_editable(true);
+ entry.set_wrap_mode(gtk4::WrapMode::Word);
+ let ctrl = gtk4::EventControllerFocus::new();
+ entry.add_controller(&ctrl);
+
+ let obj = self.instance();
+ ctrl.connect_leave(glib::clone!(@weak entry, @weak obj => move |_| {
+ let buffer = entry.buffer();
+ let start = buffer.start_iter();
+ let end = buffer.end_iter();
+ obj.imp().emit_metadata_changed(id, &PropertyValue::String(buffer.text(&start, &end,
true).to_string()));
+ }));
+
+ entry.upcast()
+ }
+ }
+ fn create_string_widget(&self, readonly: bool, id: u32) -> gtk4::Widget {
+ if readonly {
+ let label = gtk4::Label::new(None);
+ label.set_xalign(0.0);
+ label.set_yalign(0.5);
+ label.set_ellipsize(gtk4::pango::EllipsizeMode::Middle);
+
+ label.upcast()
+ } else {
+ let entry = gtk4::Entry::new();
+ entry.set_has_frame(false);
+ let ctrl = gtk4::EventControllerFocus::new();
+ entry.add_controller(&ctrl);
+
+ let obj = self.instance();
+ ctrl.connect_leave(glib::clone!(@weak entry, @weak obj => move |_| {
+ obj.imp().emit_metadata_changed(id, &PropertyValue::String(entry.text().to_string()));
+ }));
+
+ entry.upcast()
+ }
+ }
+
+ fn create_string_array_widget(&self, readonly: bool, id: u32) -> gtk4::Widget {
+ let ttv = TokenTextView::new();
+ if !readonly {
+ let ctrl = gtk4::EventControllerFocus::new();
+ ttv.add_controller(&ctrl);
+
+ let obj = self.instance();
+ ctrl.connect_leave(glib::clone!(@weak ttv, @weak obj => move |_| {
+ obj.imp().emit_metadata_changed(id, &PropertyValue::StringArray(ttv.tokens()));
+ }));
+ }
+
+ ttv.upcast()
+ }
+
+ fn create_date_widget(&self, readonly: bool, id: u32) -> gtk4::Widget {
+ self.create_string_widget(readonly, id)
+ }
+
+ fn create_widgets_for_format(&self, fmt: &MetadataSectionFormat) {
+ for (i, f) in fmt.formats.iter().enumerate() {
+ let label = gtk4::Label::new(Some(&format!("<b>{}</b>", &f.label)));
+ label.set_use_markup(true);
+ label.set_xalign(0.0);
+ if f.type_ != MetaDT::STRING_ARRAY {
+ label.set_yalign(0.5);
+ } else {
+ label.set_yalign(0.0);
+ }
+ let w = match f.type_ {
+ MetaDT::STAR_RATING => self.create_star_rating_widget(f.readonly, f.id),
+ MetaDT::STRING_ARRAY => self.create_string_array_widget(f.readonly, f.id),
+ MetaDT::TEXT => self.create_text_widget(f.readonly, f.id),
+ MetaDT::DATE => self.create_date_widget(f.readonly, f.id),
+ _ => self.create_string_widget(f.readonly, f.id),
+ };
+ let row = i as i32;
+ self.widget.insert_row(row + 1);
+ self.widget.attach(&label, 0, row, 1, 1);
+ self.widget
+ .attach_next_to(&w, Some(&label), gtk4::PositionType::Right, 1, 1);
+ self.data_map.borrow_mut().insert(f.id, w);
+ }
+ }
+
+ fn add_data(&self, fmt: &MetadataFormat, value: &PropertyValue) {
+ let data_map = self.data_map.borrow();
+ let w = data_map.get(&fmt.id);
+
+ if w.is_none() {
+ err_out!("No widget for property {}", fmt.id);
+ return;
+ }
+
+ let w = w.as_ref().unwrap();
+ match fmt.type_ {
+ MetaDT::FRAC_DEC => self.set_fraction_dec_data(w, value),
+ MetaDT::FRAC => self.set_fraction_data(w, value),
+ MetaDT::STAR_RATING => self.set_star_rating_data(w, value),
+ MetaDT::STRING_ARRAY => self.set_string_array_data(w, fmt.readonly, value),
+ MetaDT::TEXT => self.set_text_data(w, fmt.readonly, value),
+ MetaDT::DATE => self.set_date_data(w, value),
+ _ => {
+ if !self.set_text_data(w, fmt.readonly, value) {
+ err_out!("failed to set value for {}", fmt.id);
+ false
+ } else {
+ true
+ }
+ }
+ };
+ }
+
+ pub(super) fn set_data_format(&self, fmt: Option<MetadataSectionFormat>) {
+ self.fmt.replace(fmt);
+ if let Some(fmt) = self.fmt.borrow().as_ref() {
+ self.create_widgets_for_format(fmt);
+ }
+ // XXX what if None? Should we delete the widgets?
+ }
+
+ pub(super) fn set_data_source(&self, properties: Option<PropertyBag<u32>>) {
+ self.current_data.replace(properties);
+ self.data_map.borrow().values().for_each(clear_widget);
+
+ let is_empty = self
+ .current_data
+ .borrow()
+ .as_ref()
+ .map(|v| v.is_empty())
+ .unwrap_or(true);
+ self.instance().set_sensitive(!is_empty);
+ if is_empty {
+ return;
+ }
+ let properties = self.current_data.borrow();
+ if let Some(fmt) = self.fmt.borrow().as_ref() {
+ fmt.formats.iter().for_each(|f| {
+ if let Some(value) = properties.as_ref().and_then(|v| v.value(&f.id)) {
+ self.add_data(f, value)
+ } else {
+ // XXX value is empty
+ }
+ });
+ }
+ }
+
+ fn set_fraction_dec_data(&self, w: >k4::Widget, value: &PropertyValue) -> bool {
+ if let Some(s) = value.string() {
+ dbg_out!("set faction dec {}", s);
+ return if let Some(w) = w.downcast_ref::<gtk4::Label>() {
+ let dec_str = crate::fraction_to_decimal(s)
+ .map(|dec| dec.to_string())
+ .unwrap_or_else(|| "NaN".to_string());
+
+ w.set_text(&dec_str);
+ true
+ } else {
+ err_out!("Incorrect widget type {}", w.type_().name());
+ false
+ };
+ }
+
+ err_out!("Data not a string");
+ false
+ }
+
+ fn set_fraction_data(&self, w: >k4::Widget, value: &PropertyValue) -> bool {
+ if let Some(s) = value.string() {
+ dbg_out!("set fraction {}", s);
+ return if let Some(w) = w.downcast_ref::<gtk4::Label>() {
+ if let Some((n, d)) = crate::parse_fraction(s) {
+ let frac_str = format!("{}/{}", n, d);
+ w.set_text(&frac_str);
+ true
+ } else {
+ err_out!("Invalid fraction {}", s);
+ false
+ }
+ } else {
+ err_out!("Incorrect widget type {}", w.type_().name());
+ false
+ };
+ }
+
+ err_out!("Data not a string");
+ false
+ }
+
+ fn set_star_rating_data(&self, w: >k4::Widget, value: &PropertyValue) -> bool {
+ if let Some(i) = value.integer() {
+ return if let Some(w) = w.downcast_ref::<RatingLabel>() {
+ w.set_rating(i);
+ true
+ } else {
+ err_out!("Incorrect widget type {}", w.type_().name());
+ false
+ };
+ }
+
+ err_out!("Data not integer");
+ false
+ }
+
+ fn set_string_array_data(
+ &self,
+ w: >k4::Widget,
+ readonly: bool,
+ value: &PropertyValue,
+ ) -> bool {
+ if let Some(tokens) = value.string_array() {
+ return if let Some(w) = w.downcast_ref::<TokenTextView>() {
+ w.set_tokens(tokens);
+ w.set_editable(!readonly);
+ true
+ } else {
+ err_out!("Incorrect widget type {}", w.type_().name());
+ false
+ };
+ }
+ err_out!("Data not string array");
+ false
+ }
+
+ fn set_text_data(&self, w: >k4::Widget, readonly: bool, value: &PropertyValue) -> bool {
+ if let Some(s) = value.string() {
+ if readonly {
+ return if let Some(w) = w.downcast_ref::<gtk4::Label>() {
+ w.set_text(s);
+ true
+ } else {
+ err_out!("Incorrect widget type {}", w.type_().name());
+ false
+ };
+ } else {
+ return if let Some(w) = w.downcast_ref::<gtk4::Entry>() {
+ w.set_text(s);
+ true
+ } else if let Some(w) = w.downcast_ref::<gtk4::TextView>() {
+ w.buffer().set_text(s);
+ true
+ } else {
+ err_out!("Incorrect widget type {}", w.type_().name());
+ false
+ };
+ }
+ }
+
+ err_out!("Data not a string");
+ false
+ }
+
+ fn set_date_data(&self, w: >k4::Widget, value: &PropertyValue) -> bool {
+ if let Some(d) = value.date() {
+ return if let Some(w) = w.downcast_ref::<gtk4::Label>() {
+ w.set_text(&d.to_string());
+ true
+ } else {
+ err_out!("Incorrect widget type {}", w.type_().name());
+ false
+ };
+ }
+
+ err_out!("Data not a date");
+ false
+ }
+
+ fn emit_metadata_changed(&self, prop: u32, value: &PropertyValue) {
+ let mut props = WrappedPropertyBag::default();
+ let mut old_props = WrappedPropertyBag::default();
+ props.set_value(prop, value.clone());
+ if let Some(old_val) = self
+ .current_data
+ .borrow()
+ .as_ref()
+ .and_then(|props| props.value(&prop))
+ {
+ old_props.set_value(prop, old_val.clone());
+ }
+ self.instance()
+ .emit_by_name::<()>("metadata-changed", &[&props, &old_props]);
+ }
+ }
+
+ impl ObjectImpl for MetadataWidget {
+ fn constructed(&self, obj: &Self::Type) {
+ self.parent_constructed(obj);
+
+ self.widget.set_column_homogeneous(true);
+ self.widget.set_row_homogeneous(false);
+ self.widget.insert_column(0);
+ self.widget.insert_column(0);
+ self.widget.set_margin_start(8);
+ obj.upcast_ref::<super::ToolboxItem>()
+ .set_child(Some(&self.widget));
+ }
+
+ fn signals() -> &'static [Signal] {
+ use once_cell::sync::Lazy;
+ static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
+ vec![Signal::builder(
+ "metadata-changed",
+ &[
+ <WrappedPropertyBag>::static_type().into(),
+ <WrappedPropertyBag>::static_type().into(),
+ ],
+ <()>::static_type().into(),
+ )
+ .run_last()
+ .build()]
+ });
+ SIGNALS.as_ref()
+ }
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for MetadataWidget {
+ const NAME: &'static str = "NpcMetadataWidget";
+ type Type = super::MetadataWidget;
+ type ParentType = super::ToolboxItem;
+
+ fn new() -> Self {
+ Self {
+ widget: gtk4::Grid::new(),
+ data_map: RefCell::new(HashMap::default()),
+ current_data: RefCell::new(None),
+ fmt: RefCell::new(None),
+ }
+ }
+ }
+
+ impl ToolboxItemImpl for MetadataWidget {}
+ impl BoxImpl for MetadataWidget {}
+ impl WidgetImpl for MetadataWidget {}
+}
diff --git a/crates/npc-fwk/src/toolkit/widgets/rating_label.rs
b/crates/npc-fwk/src/toolkit/widgets/rating_label.rs
index 56a2c6d0..ef114566 100644
--- a/crates/npc-fwk/src/toolkit/widgets/rating_label.rs
+++ b/crates/npc-fwk/src/toolkit/widgets/rating_label.rs
@@ -17,13 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-use libc::c_int;
use std::cell::Cell;
use gdk4::prelude::*;
use glib::subclass::prelude::*;
use glib::subclass::Signal;
-use glib::translate::*;
use gtk4::prelude::*;
use gtk4::subclass::prelude::*;
@@ -55,6 +53,10 @@ impl RatingLabelPriv {
self.editable.set(editable);
}
+ fn rating(&self) -> i32 {
+ self.rating.get()
+ }
+
fn set_rating(&self, rating: i32) {
self.rating.set(rating);
let w = self.instance();
@@ -154,15 +156,37 @@ impl ObjectImpl for RatingLabelPriv {
pub trait RatingLabelExt {
fn set_rating(&self, rating: i32);
+ fn rating(&self) -> i32;
}
impl RatingLabelExt for RatingLabel {
fn set_rating(&self, rating: i32) {
self.imp().set_rating(rating);
}
+
+ fn rating(&self) -> i32 {
+ self.imp().rating()
+ }
}
impl RatingLabel {
+ /// Connect to the signal `rating-changed`
+ pub fn connect_rating_changed<F>(&self, f: F) -> glib::SignalHandlerId
+ where
+ F: Fn(&Self, i32) + 'static,
+ {
+ self.connect_local(
+ "rating-changed",
+ true,
+ glib::clone!(@weak self as w => @default-return None, move |values| {
+ if let Ok(rating) = values[0].get::<i32>() {
+ f(&w, rating);
+ }
+ None
+ }),
+ )
+ }
+
pub fn star() -> gdk4::Texture {
PIXBUFS.star.clone()
}
@@ -246,25 +270,3 @@ impl WidgetImpl for RatingLabelPriv {
RatingLabel::draw_rating(snapshot, rating, &star, &RatingLabel::unstar(), x, y);
}
}
-
-#[no_mangle]
-pub extern "C" fn fwk_rating_label_new(rating: c_int, editable: bool) -> *mut gtk4_sys::GtkWidget {
- RatingLabel::new(rating, editable)
- .upcast::<gtk4::Widget>()
- .to_glib_full()
-}
-
-/// Set the rating for the %RatingLabel widget
-///
-/// # Safety
-/// Dereference the widget pointer.
-#[no_mangle]
-pub unsafe extern "C" fn fwk_rating_label_set_rating(
- widget: *mut gtk4_sys::GtkWidget,
- rating: i32,
-) {
- let rating_label = gtk4::Widget::from_glib_none(widget)
- .downcast::<RatingLabel>()
- .expect("Not a RatingLabel widget");
- rating_label.set_rating(rating);
-}
diff --git a/crates/npc-fwk/src/toolkit/widgets/token_text_view.rs
b/crates/npc-fwk/src/toolkit/widgets/token_text_view.rs
index 36c25b36..33452806 100644
--- a/crates/npc-fwk/src/toolkit/widgets/token_text_view.rs
+++ b/crates/npc-fwk/src/toolkit/widgets/token_text_view.rs
@@ -30,8 +30,11 @@ glib::wrapper! {
impl TokenTextView {
pub fn new() -> TokenTextView {
- glib::Object::new(&[("wrap-mode", >k4::WrapMode::Word)])
- .expect("Failed to create TokenTextView Widget")
+ glib::Object::new(&[
+ ("wrap-mode", >k4::WrapMode::Word),
+ ("accepts-tab", &false),
+ ])
+ .expect("Failed to create TokenTextView Widget")
}
/// Get the tokens from the text.
diff --git a/crates/npc-fwk/src/toolkit/widgets/toolbox_item.rs
b/crates/npc-fwk/src/toolkit/widgets/toolbox_item.rs
index 21ddec50..2f219e44 100644
--- a/crates/npc-fwk/src/toolkit/widgets/toolbox_item.rs
+++ b/crates/npc-fwk/src/toolkit/widgets/toolbox_item.rs
@@ -40,6 +40,10 @@ impl ToolboxItem {
obj.imp().expander.set_label(Some(label));
obj
}
+
+ pub fn set_title(&self, title: &str) {
+ self.imp().expander.set_label(Some(title));
+ }
}
pub trait ToolboxItemExt {
diff --git a/niepce-main/Cargo.toml b/niepce-main/Cargo.toml
index 8caae616..639ac530 100644
--- a/niepce-main/Cargo.toml
+++ b/niepce-main/Cargo.toml
@@ -7,21 +7,22 @@ edition = "2018"
[dependencies]
async-channel = "1.6.1"
-once_cell = "^1.12.0"
-gettext-rs = "0.3.0"
-glib = "*"
-gio-sys = "*"
-gio = "*"
cairo-rs = "*"
+cxx = { version = "1.0", features = [ "c++17" ] }
gdk4 = "*"
gdk-pixbuf = "*"
gdk-pixbuf-sys = "*"
+gettext-rs = "0.3.0"
+gio-sys = "*"
+gio = "*"
+glib = "*"
graphene-rs = "0.15.1"
gtk4-sys = "*"
gtk4 = "*"
lazy_static = "^1.4.0"
libc = "0.2.39"
#gphoto = "0.1.1"
+once_cell = "^1.12.0"
npc-fwk = { path = "../crates/npc-fwk" }
npc-engine = { path = "../crates/npc-engine" }
diff --git a/niepce-main/src/lib.rs b/niepce-main/src/lib.rs
index 1b0d43a8..830a2e28 100644
--- a/niepce-main/src/lib.rs
+++ b/niepce-main/src/lib.rs
@@ -22,9 +22,7 @@ pub mod niepce;
use std::sync::Once;
-/// Call this to initialize npc-fwk the gtk-rs bindings
-#[no_mangle]
-pub extern "C" fn niepce_init() {
+fn niepce_init() {
static START: Once = Once::new();
START.call_once(|| {
@@ -32,3 +30,24 @@ pub extern "C" fn niepce_init() {
npc_fwk::init();
});
}
+
+use crate::niepce::ui::metadata_pane_controller::get_format;
+use npc_fwk::toolkit;
+
+#[cxx::bridge(namespace = "npc")]
+mod ffi {
+ extern "Rust" {
+ fn niepce_init();
+ }
+
+ #[namespace = "fwk"]
+ extern "C++" {
+ include!("fwk/cxx_widgets_bindings.hpp");
+
+ type MetadataSectionFormat = crate::toolkit::widgets::MetadataSectionFormat;
+ }
+
+ extern "Rust" {
+ fn get_format() -> &'static [MetadataSectionFormat];
+ }
+}
diff --git a/niepce-main/src/niepce/ui.rs b/niepce-main/src/niepce/ui.rs
index 47771336..805768e5 100644
--- a/niepce-main/src/niepce/ui.rs
+++ b/niepce-main/src/niepce/ui.rs
@@ -1,7 +1,7 @@
/*
* niepce - niepce/ui/mod.rs
*
- * Copyright (C) 2020 Hubert Figuière
+ * Copyright (C) 2022 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
@@ -22,5 +22,6 @@ pub mod image_grid_view;
pub mod image_list_store;
pub mod imagetoolbar;
pub mod library_cell_renderer;
+pub mod metadata_pane_controller;
pub mod thumb_nav;
pub mod thumb_strip_view;
diff --git a/niepce-main/src/niepce/ui/metadata_pane_controller.rs
b/niepce-main/src/niepce/ui/metadata_pane_controller.rs
new file mode 100644
index 00000000..083d1183
--- /dev/null
+++ b/niepce-main/src/niepce/ui/metadata_pane_controller.rs
@@ -0,0 +1,61 @@
+use gettextrs::gettext as i18n;
+
+use npc_engine::db::NiepcePropertyIdx;
+use npc_fwk::toolkit::widgets::{MetaDT, MetadataFormat, MetadataSectionFormat};
+
+lazy_static::lazy_static! {
+ static ref FORMATS: Vec<MetadataSectionFormat> = vec![
+ MetadataSectionFormat{
+ section: i18n("File Information"),
+ formats: vec![
+ MetadataFormat{ label: i18n("File Name:"), id: NiepcePropertyIdx::NpFileNameProp as u32,
type_: MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("Folder:"), id: NiepcePropertyIdx::NpFolderProp as u32,
type_:MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("File Type:"), id: NiepcePropertyIdx::NpFileTypeProp as u32,
type_:MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("File Size:"), id: NiepcePropertyIdx::NpFileSizeProp as u32,
type_:MetaDT::SIZE, readonly: true },
+ MetadataFormat{ label: i18n("Sidecar Files:"), id: NiepcePropertyIdx::NpSidecarsProp as u32,
type_:MetaDT::STRING_ARRAY, readonly: true },
+ ]
+ },
+ MetadataSectionFormat{
+ section: i18n("Camera Information"),
+ formats: vec![
+ MetadataFormat{ label: i18n("Make:"), id: NiepcePropertyIdx::NpTiffMakeProp as u32,
type_:MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("Model:"), id: NiepcePropertyIdx::NpTiffModelProp as u32,
type_:MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("Lens:"), id: NiepcePropertyIdx::NpExifAuxLensProp as u32,
type_:MetaDT::STRING, readonly: true },
+ ]
+ },
+ MetadataSectionFormat{
+ section: i18n("Shooting Information"),
+ formats: vec![
+ MetadataFormat{ label: i18n("Exposure Program:"), id:
NiepcePropertyIdx::NpExifExposureProgramProp as u32, type_:MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("Speed:"), id: NiepcePropertyIdx::NpExifExposureTimeProp as u32,
type_:MetaDT::FRAC, readonly: true },
+ MetadataFormat{ label: i18n("Aperture:"), id: NiepcePropertyIdx::NpExifFNumberPropProp as
u32, type_:MetaDT::FRAC_DEC, readonly: true },
+ MetadataFormat{ label: i18n("ISO:"), id: NiepcePropertyIdx::NpExifIsoSpeedRatingsProp as
u32, type_:MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("Exposure Bias:"), id: NiepcePropertyIdx::NpExifExposureBiasProp
as u32, type_:MetaDT::FRAC_DEC, readonly: true },
+ MetadataFormat{ label: i18n("Flash:"), id: NiepcePropertyIdx::NpExifFlashFiredProp as u32,
type_:MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("Flash compensation:"), id:
NiepcePropertyIdx::NpExifAuxFlashCompensationProp as u32, type_:MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("Focal length:"), id: NiepcePropertyIdx::NpExifFocalLengthProp
as u32, type_:MetaDT::FRAC_DEC, readonly: true },
+ MetadataFormat{ label: i18n("White balance:"), id: NiepcePropertyIdx::NpExifWbProp as u32,
type_:MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("Date:"), id: NiepcePropertyIdx::NpExifDateTimeOriginalProp as
u32, type_:MetaDT::DATE, readonly: false },
+ ]
+ },
+ MetadataSectionFormat{
+ section: i18n("IPTC"),
+ formats: vec![
+ MetadataFormat{ label: i18n("Headline:"), id: NiepcePropertyIdx::NpIptcHeadlineProp as u32,
type_:MetaDT::STRING, readonly: false },
+ MetadataFormat{ label: i18n("Caption:"), id: NiepcePropertyIdx::NpIptcDescriptionProp as
u32, type_:MetaDT::TEXT, readonly: false },
+ MetadataFormat{ label: i18n("Rating:"), id: NiepcePropertyIdx::NpXmpRatingProp as u32,
type_:MetaDT::STAR_RATING, readonly: false },
+ // FIXME change this type to the right one when there is a widget
+ MetadataFormat{ label: i18n("Label:"), id: NiepcePropertyIdx::NpXmpLabelProp as u32,
type_:MetaDT::STRING, readonly: true },
+ MetadataFormat{ label: i18n("Keywords:"), id: NiepcePropertyIdx::NpIptcKeywordsProp as u32,
type_:MetaDT::STRING_ARRAY, readonly: false },
+ ]
+ },
+ MetadataSectionFormat{
+ section: i18n("Rights"),
+ formats: vec![]
+ },
+ ];
+}
+
+pub fn get_format() -> &'static [MetadataSectionFormat] {
+ &FORMATS
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index cbfb8686..22fea51c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -27,7 +27,6 @@ RUST_SOURCES = \
@top_srcdir@/crates/npc-engine/src/library/thumbnail_cache.rs \
@top_srcdir@/crates/npc-engine/src/lib.rs \
@top_srcdir@/crates/npc-fwk/Cargo.toml \
- @top_srcdir@/crates/npc-fwk/build.rs \
@top_srcdir@/crates/npc-fwk/src/base.rs \
@top_srcdir@/crates/npc-fwk/src/base/date.rs \
@top_srcdir@/crates/npc-fwk/src/base/debug.rs \
@@ -44,6 +43,7 @@ RUST_SOURCES = \
@top_srcdir@/crates/npc-fwk/src/toolkit/movieutils.rs \
@top_srcdir@/crates/npc-fwk/src/toolkit/thumbnail.rs \
@top_srcdir@/crates/npc-fwk/src/toolkit/widgets.rs \
+ @top_srcdir@/crates/npc-fwk/src/toolkit/widgets/metadata_widget.rs \
@top_srcdir@/crates/npc-fwk/src/toolkit/widgets/rating_label.rs \
@top_srcdir@/crates/npc-fwk/src/toolkit/widgets/token_text_view.rs \
@top_srcdir@/crates/npc-fwk/src/toolkit/widgets/toolbox_item.rs \
diff --git a/src/engine/db/libmetadata.cpp b/src/engine/db/libmetadata.cpp
index 324506c5..0537cc3f 100644
--- a/src/engine/db/libmetadata.cpp
+++ b/src/engine/db/libmetadata.cpp
@@ -1,7 +1,7 @@
/*
* niepce - db/libmetadata.cpp
*
- * Copyright (C) 2008-2021 Hubert Figuière
+ * Copyright (C) 2008-2022 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
@@ -27,6 +27,12 @@ fwk::PropertyBagPtr libmetadata_to_properties(const LibMetadata* meta,
return fwk::property_bag_wrap(ffi::engine_libmetadata_to_properties(meta, &propset));
}
+fwk::WrappedPropertyBagPtr libmetadata_to_wrapped_properties(const LibMetadata* meta,
+ const fwk::PropertySet& propset)
+{
+ return fwk::wrapped_property_bag_wrap(ffi::engine_libmetadata_to_wrapped_properties(meta, &propset));
+}
+
}
/*
diff --git a/src/engine/db/libmetadata.hpp b/src/engine/db/libmetadata.hpp
index 5b92fbfa..22e347b9 100644
--- a/src/engine/db/libmetadata.hpp
+++ b/src/engine/db/libmetadata.hpp
@@ -1,7 +1,7 @@
/*
* niepce - eng/db/libmetadata.hpp
*
- * Copyright (C) 2008-2021 Hubert Figuière
+ * Copyright (C) 2008-2022 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
@@ -28,6 +28,8 @@ namespace eng {
fwk::PropertyBagPtr libmetadata_to_properties(const LibMetadata *meta,
const fwk::PropertySet &propset);
+fwk::WrappedPropertyBagPtr libmetadata_to_wrapped_properties(const LibMetadata* meta,
+ const fwk::PropertySet& propset);
}
diff --git a/src/fwk/Makefile.am b/src/fwk/Makefile.am
index 48f729b8..1e1f426e 100644
--- a/src/fwk/Makefile.am
+++ b/src/fwk/Makefile.am
@@ -21,6 +21,14 @@ cxx_fwk_bindings.hpp: $(top_srcdir)/crates/npc-fwk/src/lib.rs
@echo "Generating bindings header $@..."
@$(RUST_CXXBRIDGE) --header $< > $@
+cxx_widgets_bindings.cpp: $(top_srcdir)/crates/npc-fwk/src/toolkit/widgets/metadata_widget.rs
+ @echo "Generating bindings $@..."
+ @$(RUST_CXXBRIDGE) $< > $@
+
+cxx_widgets_bindings.hpp: $(top_srcdir)/crates/npc-fwk/src/toolkit/widgets/metadata_widget.rs
+ @echo "Generating bindings header $@..."
+ @$(RUST_CXXBRIDGE) --header $< > $@
+
cxx_eng_bindings.cpp: $(top_srcdir)/crates/npc-engine/src/lib.rs
@echo "Generating bindings $@..."
@$(RUST_CXXBRIDGE) $< > $@
@@ -29,12 +37,25 @@ cxx_eng_bindings.hpp: $(top_srcdir)/crates/npc-engine/src/lib.rs
@echo "Generating bindings header $@..."
@$(RUST_CXXBRIDGE) --header $< > $@
+cxx_npc_bindings.cpp: $(top_srcdir)/niepce-main/src/lib.rs
+ @echo "Generating bindings $@..."
+ @$(RUST_CXXBRIDGE) $< > $@
+
+cxx_npc_bindings.hpp: $(top_srcdir)/niepce-main/src/lib.rs
+ @echo "Generating bindings header $@..."
+ @$(RUST_CXXBRIDGE) --header $< > $@
+
BUILT_SOURCES = \
cxx_colour_bindings.cpp \
cxx_colour_bindings.hpp \
cxx_fwk_bindings.cpp \
cxx_fwk_bindings.hpp \
cxx_eng_bindings.cpp \
- cxx_eng_bindings.hpp
+ cxx_eng_bindings.hpp \
+ cxx_widgets_bindings.cpp \
+ cxx_widgets_bindings.hpp \
+ cxx_npc_bindings.cpp \
+ cxx_npc_bindings.hpp \
+ $(NULL)
CLEANFILES = $(BUILD_SOURCES)
diff --git a/src/fwk/base/propertybag.cpp b/src/fwk/base/propertybag.cpp
index aa6ec429..d7bf910a 100644
--- a/src/fwk/base/propertybag.cpp
+++ b/src/fwk/base/propertybag.cpp
@@ -45,9 +45,9 @@ PropertyBagPtr property_bag_wrap(PropertyBag* bag)
return PropertyBagPtr(bag, &ffi::eng_property_bag_delete);
}
-PropertyBagPtr property_bag_new()
+WrappedPropertyBagPtr wrapped_property_bag_wrap(WrappedPropertyBag* bag)
{
- return property_bag_wrap(ffi::eng_property_bag_new());
+ return WrappedPropertyBagPtr(bag, &ffi::fwk_wrapped_property_bag_delete);
}
PropertyValuePtr property_bag_value(const PropertyBagPtr& bag, PropertyIndex idx)
@@ -55,6 +55,11 @@ PropertyValuePtr property_bag_value(const PropertyBagPtr& bag, PropertyIndex idx
return PropertyValuePtr::from_raw(ffi::eng_property_bag_value(bag.get(), idx));
}
+PropertyValuePtr wrapped_property_bag_value(const WrappedPropertyBagPtr& bag, PropertyIndex idx)
+{
+ return PropertyValuePtr::from_raw(ffi::fwk_property_bag_value(bag.get(), idx));
+}
+
bool set_value_for_property(PropertyBag& bag, ffi::NiepcePropertyIdx idx,
const PropertyValue& value)
{
diff --git a/src/fwk/base/propertybag.hpp b/src/fwk/base/propertybag.hpp
index 30918037..7d3897d8 100644
--- a/src/fwk/base/propertybag.hpp
+++ b/src/fwk/base/propertybag.hpp
@@ -44,11 +44,14 @@ PropertySetPtr property_set_new();
*/
typedef std::shared_ptr<PropertyBag> PropertyBagPtr;
-PropertyBagPtr property_bag_new();
PropertyBagPtr property_bag_wrap(PropertyBag*);
-
PropertyValuePtr property_bag_value(const PropertyBagPtr& bag, PropertyIndex key);
+typedef std::shared_ptr<WrappedPropertyBag> WrappedPropertyBagPtr;
+
+WrappedPropertyBagPtr wrapped_property_bag_wrap(WrappedPropertyBag* bag);
+PropertyValuePtr wrapped_property_bag_value(const WrappedPropertyBagPtr& bag, PropertyIndex key);
+
/** return true if a property was removed prior to insertion */
bool set_value_for_property(PropertyBag&, ffi::NiepcePropertyIdx idx, const PropertyValue& value);
/** return property or an empty option */
diff --git a/src/fwk/cxx_prelude.hpp b/src/fwk/cxx_prelude.hpp
new file mode 100644
index 00000000..65283892
--- /dev/null
+++ b/src/fwk/cxx_prelude.hpp
@@ -0,0 +1,12 @@
+/*
+ * niepce - fwk/cxx_prelude.hpp
+ */
+
+#pragma once
+
+// things that need to be declared before anything.
+// early "extern C++"
+// And that the implementation needs too.
+namespace fwk {
+class WrappedPropertyBag;
+}
diff --git a/src/fwk/toolkit/Makefile.am b/src/fwk/toolkit/Makefile.am
index 41ac621a..94c00af4 100644
--- a/src/fwk/toolkit/Makefile.am
+++ b/src/fwk/toolkit/Makefile.am
@@ -37,6 +37,8 @@ libniepceframework_a_SOURCES = \
../cxx_colour_bindings.cpp \
../cxx_fwk_bindings.cpp \
../cxx_eng_bindings.cpp \
+ ../cxx_widgets_bindings.cpp \
+ ../cxx_npc_bindings.cpp \
application.hpp application.cpp \
appframe.hpp appframe.cpp \
dialog.hpp dialog.cpp \
@@ -57,10 +59,7 @@ libniepceframework_a_SOURCES = \
widgets/toolboxitemwidget.hpp widgets/toolboxitemwidget.cpp \
widgets/editablehscale.hpp widgets/editablehscale.cpp \
widgets/dock.cpp widgets/dock.hpp \
- widgets/notabtextview.hpp widgets/notabtextview.cpp \
- widgets/tokentextview.hpp widgets/tokentextview.cpp \
dockable.hpp dockable.cpp \
- metadatawidget.hpp metadatawidget.cpp \
undo.hpp undo.cpp \
command.hpp \
$(NULL)
diff --git a/src/fwk/utils/init.cpp b/src/fwk/utils/init.cpp
index f19f1d54..c6525b78 100644
--- a/src/fwk/utils/init.cpp
+++ b/src/fwk/utils/init.cpp
@@ -33,7 +33,7 @@ void init()
{
Gio::init();
- ffi::niepce_init();
+ npc::niepce_init();
}
diff --git a/src/niepce/ui/gridviewmodule.cpp b/src/niepce/ui/gridviewmodule.cpp
index 1746291b..3f99a707 100644
--- a/src/niepce/ui/gridviewmodule.cpp
+++ b/src/niepce/ui/gridviewmodule.cpp
@@ -236,8 +236,8 @@ void GridViewModule::select_image(eng::library_id_t id)
}
}
-void GridViewModule::on_metadata_changed(const fwk::PropertyBagPtr & props,
- const fwk::PropertyBagPtr & old)
+void GridViewModule::on_metadata_changed(const fwk::WrappedPropertyBagPtr& props,
+ const fwk::WrappedPropertyBagPtr& old)
{
// TODO this MUST be more generic
DBG_OUT("on_metadata_changed()");
diff --git a/src/niepce/ui/gridviewmodule.hpp b/src/niepce/ui/gridviewmodule.hpp
index 15203958..262ffdda 100644
--- a/src/niepce/ui/gridviewmodule.hpp
+++ b/src/niepce/ui/gridviewmodule.hpp
@@ -77,11 +77,10 @@ public:
protected:
virtual Gtk::Widget * buildWidget() override;
-
private:
static bool get_colour_callback_c(int32_t label, ffi::RgbColour* out, const void* user_data);
std::optional<fwk::RgbColourPtr> get_colour_callback(int32_t label) const;
- void on_metadata_changed(const fwk::PropertyBagPtr&, const fwk::PropertyBagPtr& old);
+ void on_metadata_changed(const fwk::WrappedPropertyBagPtr&, const fwk::WrappedPropertyBagPtr& old);
static void on_rating_changed(GtkCellRenderer*, eng::library_id_t id, int rating,
gpointer user_data);
void on_librarylistview_click(const Glib::RefPtr<Gtk::GestureClick>& gesture, double, double);
diff --git a/src/niepce/ui/metadatapanecontroller.cpp b/src/niepce/ui/metadatapanecontroller.cpp
index 8c336e73..e8e56554 100644
--- a/src/niepce/ui/metadatapanecontroller.cpp
+++ b/src/niepce/ui/metadatapanecontroller.cpp
@@ -24,78 +24,28 @@
#include <gtkmm/entry.h>
#include "fwk/base/debug.hpp"
-#include "fwk/toolkit/metadatawidget.hpp"
#include "engine/db/properties.hpp"
#include "engine/db/libmetadata.hpp"
#include "metadatapanecontroller.hpp"
+#include "rust_bindings.hpp"
+
namespace ui {
using ffi::NiepcePropertyIdx;
-const std::vector<fwk::MetaDataSectionFormat>&
-MetaDataPaneController::get_format()
-{
- static const std::vector<fwk::MetaDataSectionFormat> s_format = {
- { _("File Information"),
- {
- { _("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"),
- {
- { _("Make:"), NiepcePropertyIdx::NpTiffMakeProp, fwk::MetaDT::STRING, true },
- { _("Model:"), NiepcePropertyIdx::NpTiffModelProp, fwk::MetaDT::STRING, true },
- { _("Lens:"), NiepcePropertyIdx::NpExifAuxLensProp, fwk::MetaDT::STRING, true },
- }
- },
- { _("Shooting Information"),
- {
- { _("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"),
- {
- { _("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"),
- std::vector<fwk::MetaDataFormat>()
- },
- };
- return s_format;
-}
-
const fwk::PropertySet* MetaDataPaneController::get_property_set()
{
static fwk::PropertySet* propset = nullptr;
if(!propset) {
propset = ffi::eng_property_set_new();
- const std::vector<fwk::MetaDataSectionFormat>& formats = get_format();
+ rust::Slice<const fwk::MetadataSectionFormat> formats = npc::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);
+ ffi::eng_property_set_add(propset, (NiepcePropertyIdx)format->id);
format++;
}
current++;
@@ -113,9 +63,25 @@ MetaDataPaneController::MetaDataPaneController()
MetaDataPaneController::~MetaDataPaneController()
{
+ for (const auto& w : m_widgets) {
+ auto w_ptr = reinterpret_cast<GtkWidget*>(w.first->gobj());
+ g_signal_handler_disconnect(w_ptr, w.second);
+ }
}
-Gtk::Widget *
+void
+MetaDataPaneController::metadata_changed_cb(GtkWidget*, const fwk::WrappedPropertyBag* props,
+ const fwk::WrappedPropertyBag* old_props,
+ MetaDataPaneController* self)
+{
+ self->on_metadata_changed(
+ fwk::wrapped_property_bag_wrap(
+ ffi::fwk_wrapped_property_bag_clone(props)),
+ fwk::wrapped_property_bag_wrap(
+ ffi::fwk_wrapped_property_bag_clone(old_props)));
+}
+
+Gtk::Widget *
MetaDataPaneController::buildWidget()
{
if(m_widget) {
@@ -125,25 +91,28 @@ MetaDataPaneController::buildWidget()
m_widget = box;
DBG_ASSERT(box, "dockable vbox not found");
- const auto& formats = get_format();
+ const auto& formats = npc::get_format();
auto current = formats.begin();
while (current != formats.end()) {
- auto w = Gtk::manage(new fwk::MetaDataWidget(current->section));
- box->append(*w);
- w->set_data_format(&*current);
- m_widgets.push_back(w);
- w->signal_metadata_changed.connect(
- sigc::mem_fun(*this,
- &MetaDataPaneController::on_metadata_changed));
+ auto w = fwk::MetadataWidget_new(current->section);
+ auto w_ptr = reinterpret_cast<GtkWidget*>(w->gobj());
+ DBG_ASSERT(w_ptr, "MetadataWidget is null");
+ gtk_box_append(box->gobj(), w_ptr);
+ w->set_data_format(*current);
+ auto handler = g_signal_connect(w_ptr, "metadata-changed",
+ G_CALLBACK(MetaDataPaneController::metadata_changed_cb),
+ this);
+ m_widgets.push_back(std::make_pair(std::move(w), handler));
+
current++;
}
return m_widget;
}
-void MetaDataPaneController::on_metadata_changed(const fwk::PropertyBagPtr& props,
- const fwk::PropertyBagPtr& old)
+void MetaDataPaneController::on_metadata_changed(const fwk::WrappedPropertyBagPtr& props,
+ const fwk::WrappedPropertyBagPtr& old)
{
signal_metadata_changed.emit(props, old);
}
@@ -152,15 +121,18 @@ void MetaDataPaneController::display(eng::library_id_t file_id, const eng::LibMe
{
m_fileid = file_id;
DBG_OUT("displaying metadata");
- fwk::PropertyBagPtr properties;
- if(meta) {
+ fwk::WrappedPropertyBagPtr properties;
+ if (meta) {
const fwk::PropertySet* propset = get_property_set();
- properties = eng::libmetadata_to_properties(meta, *propset);
+ properties = eng::libmetadata_to_wrapped_properties(meta, *propset);
+ }
+ for (const auto& w : m_widgets) {
+ if (properties) {
+ w.first->set_data_source(*properties);
+ } else {
+ w.first->set_data_source_none();
+ }
}
- std::for_each(m_widgets.begin(), m_widgets.end(),
- [properties] (decltype(m_widgets)::value_type w) {
- w->set_data_source(properties);
- });
}
}
diff --git a/src/niepce/ui/metadatapanecontroller.hpp b/src/niepce/ui/metadatapanecontroller.hpp
index 6c53065d..f7eb9643 100644
--- a/src/niepce/ui/metadatapanecontroller.hpp
+++ b/src/niepce/ui/metadatapanecontroller.hpp
@@ -19,16 +19,14 @@
#pragma once
-#include <gtkmm/box.h>
-
#include "engine/db/libmetadata.hpp"
#include "fwk/base/propertybag.hpp"
#include "fwk/utils/exempi.hpp"
#include "fwk/toolkit/dockable.hpp"
+#include "rust_bindings.hpp"
+
namespace fwk {
-struct MetaDataSectionFormat;
-class MetaDataWidget;
class Dock;
}
@@ -46,14 +44,16 @@ public:
eng::library_id_t displayed_file() const
{ return m_fileid; }
- sigc::signal<void(const fwk::PropertyBagPtr &, const fwk::PropertyBagPtr &)> signal_metadata_changed;
+ sigc::signal<void(const fwk::WrappedPropertyBagPtr&, const fwk::WrappedPropertyBagPtr&)>
signal_metadata_changed;
private:
- void on_metadata_changed(const fwk::PropertyBagPtr &,
- const fwk::PropertyBagPtr & old);
+ void on_metadata_changed(const fwk::WrappedPropertyBagPtr&,
+ const fwk::WrappedPropertyBagPtr& old);
+ static void metadata_changed_cb(GtkWidget*, const fwk::WrappedPropertyBag* props,
+ const fwk::WrappedPropertyBag* old_props,
+ MetaDataPaneController* self);
- std::vector<fwk::MetaDataWidget *> m_widgets;
+ std::vector<std::pair<::rust::Box<fwk::MetadataWidget>, guint>> m_widgets;
- 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 0684a420..18ea1f5f 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-2021 Hubert Figuière
+ * Copyright (C) 2008-2022 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
@@ -206,16 +206,16 @@ bool SelectionController::_set_metadata(const std::string & undo_label,
bool SelectionController::_set_metadata(const std::string & undo_label,
eng::library_id_t file_id,
- const fwk::PropertyBagPtr & props,
- const fwk::PropertyBagPtr & old)
+ const fwk::WrappedPropertyBagPtr& props,
+ const fwk::WrappedPropertyBagPtr& old)
{
auto undo = fwk::Application::app()->begin_undo(undo_label);
- auto len = eng_property_bag_len(props.get());
+ auto len = ffi::fwk_property_bag_len(props.get());
for (size_t i = 0; i < len; i++) {
- auto key = eng_property_bag_key_by_index(props.get(), i);
+ auto key = ffi::fwk_property_bag_key_by_index(props.get(), i);
// This is a shared_ptr because it's the only way to pass it to the lambda
// as Box<> isn't copyable
- auto value = std::make_shared<fwk::PropertyValuePtr>(fwk::property_bag_value(old, key));
+ auto value = std::make_shared<fwk::PropertyValuePtr>(fwk::wrapped_property_bag_value(old, key));
/*
if (!result.empty()) {
value = result.unwrap();
@@ -228,7 +228,7 @@ bool SelectionController::_set_metadata(const std::string & undo_label,
*/
auto libclient = getLibraryClient();
- auto new_value = std::make_shared<fwk::PropertyValuePtr>(fwk::property_bag_value(props, key));
+ auto new_value = std::make_shared<fwk::PropertyValuePtr>(fwk::wrapped_property_bag_value(props,
key));
undo->new_command<void>(
[libclient, file_id, key, new_value] () {
ffi::libraryclient_set_metadata(
@@ -294,8 +294,8 @@ void SelectionController::set_property(ffi::NiepcePropertyIdx idx, int value)
}
}
-void SelectionController::set_properties(const fwk::PropertyBagPtr & props,
- const fwk::PropertyBagPtr & old)
+void SelectionController::set_properties(const fwk::WrappedPropertyBagPtr& props,
+ const fwk::WrappedPropertyBagPtr& old)
{
eng::library_id_t selection = get_selection();
if (selection >= 0) {
diff --git a/src/niepce/ui/selectioncontroller.hpp b/src/niepce/ui/selectioncontroller.hpp
index fbe268cf..4d6503d8 100644
--- a/src/niepce/ui/selectioncontroller.hpp
+++ b/src/niepce/ui/selectioncontroller.hpp
@@ -94,8 +94,8 @@ public:
void set_property(ffi::NiepcePropertyIdx idx, int value);
- void set_properties(const fwk::PropertyBagPtr & props,
- const fwk::PropertyBagPtr & old);
+ void set_properties(const fwk::WrappedPropertyBagPtr& props,
+ const fwk::WrappedPropertyBagPtr& old);
/** the content will change */
void content_will_change();
@@ -119,8 +119,8 @@ private:
int old_value, int new_value);
bool _set_metadata(const std::string & undo_label,
eng::library_id_t file_id,
- const fwk::PropertyBagPtr & props,
- const fwk::PropertyBagPtr & old);
+ const fwk::WrappedPropertyBagPtr& props,
+ const fwk::WrappedPropertyBagPtr& old);
/** move the selection and emit the signal
* @param backwards true if the move is backwards.
*/
diff --git a/src/rust_bindings.hpp b/src/rust_bindings.hpp
index 9539c612..a653285c 100644
--- a/src/rust_bindings.hpp
+++ b/src/rust_bindings.hpp
@@ -25,6 +25,7 @@
#include "fwk/cxx_fwk_bindings.hpp"
#include "fwk/cxx_eng_bindings.hpp"
+#include "fwk/cxx_npc_bindings.hpp"
namespace ffi {
class rust_str;
@@ -36,6 +37,7 @@ typedef rust_str str;
typedef fwk::FileList FileList;
typedef fwk::PropertyValue PropertyValue;
typedef fwk::RgbColour RgbColour;
+typedef fwk::WrappedPropertyBag WrappedPropertyBag;
typedef eng::Label Label;
typedef eng::LibFile LibFile;
typedef eng::LibMetadata LibMetadata;
@@ -44,7 +46,6 @@ struct NiepcePropertyBag;
struct NiepcePropertySet;
}
-#include "target/fwk_bindings.h"
#include "target/eng_bindings.h"
#include "target/bindings.h"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]