[niepce] rust+ui: port the image liststore to Rust



commit 23baa54b8bae4ba9bc566f960f8986a829cbc359
Author: Hubert Figuière <hub figuiere net>
Date:   Tue Jan 28 00:36:40 2020 -0500

    rust+ui: port the image liststore to Rust
    
    - This allow to use the Rust cell renderer
    - remove the C++ cell renderer

 Cargo.lock                                    |   1 +
 Cargo.toml                                    |   1 +
 build.rs                                      |   7 +-
 crates/npc-engine/build.rs                    |   1 +
 crates/npc-engine/src/library/notification.rs |   6 +-
 src/Makefile.am                               |   1 +
 src/fwk/toolkit/widgets/imagegridview.cpp     |  19 +-
 src/fwk/toolkit/widgets/imagegridview.hpp     |  46 +---
 src/lib.rs                                    |   1 +
 src/niepce/ui/Makefile.am                     |   1 -
 src/niepce/ui/dialogs/importdialog.hpp        |   1 -
 src/niepce/ui/filmstripcontroller.cpp         |   4 +-
 src/niepce/ui/filmstripcontroller.hpp         |   4 +-
 src/niepce/ui/gridviewmodule.cpp              |  64 +++--
 src/niepce/ui/gridviewmodule.hpp              |  11 +-
 src/niepce/ui/image_list_store.rs             | 243 +++++++++++++++++
 src/niepce/ui/imageliststore.cpp              |  69 +++--
 src/niepce/ui/imageliststore.hpp              |  44 ++-
 src/niepce/ui/library_cell_renderer.rs        | 138 ++++++++--
 src/niepce/ui/librarycellrenderer.cpp         | 368 --------------------------
 src/niepce/ui/librarycellrenderer.hpp         | 119 ---------
 src/niepce/ui/mod.rs                          |   1 +
 src/niepce/ui/moduleshell.hpp                 |   2 +-
 src/niepce/ui/niepcewindow.cpp                |   4 +-
 src/niepce/ui/selectioncontroller.cpp         |   4 +-
 src/niepce/ui/selectioncontroller.hpp         |   4 +-
 src/niepce/ui/thumbstripview.cpp              |  63 ++---
 src/niepce/ui/thumbstripview.hpp              |  21 +-
 28 files changed, 510 insertions(+), 738 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index 9131555..7fc03a0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -576,6 +576,7 @@ dependencies = [
  "cbindgen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdk 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdk-pixbuf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gdk-pixbuf-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "gettext-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gio 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gio-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/Cargo.toml b/Cargo.toml
index f5d7ced..e97549b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,6 +13,7 @@ gio = "^0.8.0"
 cairo-rs = "*"
 gdk = "*"
 gdk-pixbuf = "*"
+gdk-pixbuf-sys = "*"
 gtk-sys = { version = "*", features = ["v3_22"] }
 gtk = { version = "^0.8.0", git = "https://github.com/hfiguiere/gtk.git";, branch = "0.8.0-p1" }
 libc = "0.2.39"
diff --git a/build.rs b/build.rs
index 5b08a40..a6f2fd7 100644
--- a/build.rs
+++ b/build.rs
@@ -15,10 +15,15 @@ fn main() {
             .with_namespace("ffi")
             .with_language(cbindgen::Language::Cxx)
             .with_parse_deps(true)
-            .with_parse_exclude(&["exempi", "chrono", "multimap"])
+            .with_parse_exclude(&["exempi", "chrono", "multimap", "npc_engine"])
+            .include_item("ColIndex")
+            .exclude_item("GdkPixbuf")
             .exclude_item("GtkWindow")
             .exclude_item("GtkToolbar")
+            .exclude_item("GtkTreeIter")
             .exclude_item("GtkIconView")
+            .exclude_item("GtkListStore")
+            .exclude_item("GtkTreePath")
             .exclude_item("GtkCellRenderer")
             .exclude_item("GtkWidget")
             .exclude_item("GFileInfo")
diff --git a/crates/npc-engine/build.rs b/crates/npc-engine/build.rs
index ac02cc8..ae2ae9c 100644
--- a/crates/npc-engine/build.rs
+++ b/crates/npc-engine/build.rs
@@ -69,6 +69,7 @@ fn main() {
             .with_language(cbindgen::Language::Cxx)
             .with_parse_deps(true)
             .with_parse_exclude(&["exempi", "chrono", "multimap"])
+            .include_item("Managed")
             .exclude_item("GtkWindow")
             .exclude_item("GtkToolbar")
             .exclude_item("GFileInfo")
diff --git a/crates/npc-engine/src/library/notification.rs b/crates/npc-engine/src/library/notification.rs
index e7d6e03..72531e6 100644
--- a/crates/npc-engine/src/library/notification.rs
+++ b/crates/npc-engine/src/library/notification.rs
@@ -76,9 +76,9 @@ pub struct Count {
 
 #[derive(Clone)]
 pub struct MetadataChange {
-    id: LibraryId,
-    meta: PropertyIndex,
-    value: PropertyValue,
+    pub id: LibraryId,
+    pub meta: PropertyIndex,
+    pub value: PropertyValue,
 }
 
 impl MetadataChange {
diff --git a/src/Makefile.am b/src/Makefile.am
index c0d780a..64009cb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -52,6 +52,7 @@ RUST_SOURCES = \
        @top_srcdir@/src/niepce/mod.rs \
        @top_srcdir@/src/niepce/ui/mod.rs \
        @top_srcdir@/src/niepce/ui/imagetoolbar.rs \
+       @top_srcdir@/src/niepce/ui/image_list_store.rs \
        @top_srcdir@/src/niepce/ui/dialogs/mod.rs \
        @top_srcdir@/src/niepce/ui/dialogs/confirm.rs \
        @top_srcdir@/src/niepce/ui/dialogs/requestnewfolder.rs \
diff --git a/src/fwk/toolkit/widgets/imagegridview.cpp b/src/fwk/toolkit/widgets/imagegridview.cpp
index fc5189d..714b7f6 100644
--- a/src/fwk/toolkit/widgets/imagegridview.cpp
+++ b/src/fwk/toolkit/widgets/imagegridview.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/toolkit/widgets/imagegridview.cpp
  *
- * Copyright (C) 2011-2013 Hubert Figuiere
+ * Copyright (C) 2011-2020 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
@@ -20,14 +20,9 @@
 #include "fwk/base/debug.hpp"
 #include "imagegridview.hpp"
 
-namespace fwk {
+#include "rust_bindings.hpp"
 
-void ClickableCellRenderer::hit(int x, int y)
-{
-  m_x = x;
-  m_y = y;
-  m_hit = true;
-}
+namespace fwk {
 
 ImageGridView::ImageGridView(const Glib::RefPtr<Gtk::TreeModel> & model)
   : Gtk::IconView(model)
@@ -45,12 +40,10 @@ bool ImageGridView::on_button_press_event(GdkEventButton *event)
 
   Gtk::CellRenderer* cell = nullptr;
   bool found = get_item_at_pos(event->x, event->y, cell);
-  if(found) {
-    ClickableCellRenderer* clickable_cell = dynamic_cast<ClickableCellRenderer*>(cell);
-    
-    if(clickable_cell) {
+  if (found) {
+    if (strcmp(G_OBJECT_TYPE_NAME(cell->gobj()), "LibraryCellRenderer") == 0) {
       DBG_OUT("clickable cell");
-      clickable_cell->hit(event->x, event->y);
+      ffi::npc_library_cell_renderer_hit(GTK_CELL_RENDERER(cell->gobj()), event->x, event->y);
     }
   }
 
diff --git a/src/fwk/toolkit/widgets/imagegridview.hpp b/src/fwk/toolkit/widgets/imagegridview.hpp
index 2cc2d13..6bf2080 100644
--- a/src/fwk/toolkit/widgets/imagegridview.hpp
+++ b/src/fwk/toolkit/widgets/imagegridview.hpp
@@ -1,7 +1,7 @@
 /*
  * niepce - fwk/toolkit/widgets/imagegridview.hpp
  *
- * Copyright (C) 2011-2013 Hubert Figuiere
+ * Copyright (C) 2011-2020 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,52 +17,12 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef IMAGE_GRID_VIEW_H__
-#define IMAGE_GRID_VIEW_H__
+#pragma once
 
 #include <gtkmm/iconview.h>
-#include <gtkmm/cellareabox.h>
 
 namespace fwk {
 
-/**
- * Clickable Cell Renderer
- * To work around https://bugzilla.gnome.org/show_bug.cgi?id=664368
- */
-class ClickableCellRenderer
-{
-public:
-  ClickableCellRenderer()
-    : m_x(0)
-    , m_y(0)
-    , m_hit(false)
-  {
-  }
-  /**
-   * Hit.
-   */
-  void hit(int x, int y);
-  int x() const 
-  {
-    return m_x;
-  }
-  int y() const
-  {
-    return m_y;
-  }
-  bool is_hit() const
-  {
-    return m_hit;
-  }
-  void reset_hit()
-  {
-    m_hit = false;
-  }
-private:
-  int m_x, m_y;
-  bool m_hit;
-};
-
 class ImageGridView
   : public Gtk::IconView
 {
@@ -80,5 +40,3 @@ private:
 };
 
 }
-
-#endif
diff --git a/src/lib.rs b/src/lib.rs
index dcaf462..ccc5c10 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -20,6 +20,7 @@
 extern crate cairo;
 extern crate gdk;
 extern crate gdk_pixbuf;
+extern crate gdk_pixbuf_sys;
 extern crate gettextrs;
 extern crate gio;
 extern crate gio_sys;
diff --git a/src/niepce/ui/Makefile.am b/src/niepce/ui/Makefile.am
index 52063a5..80975c0 100644
--- a/src/niepce/ui/Makefile.am
+++ b/src/niepce/ui/Makefile.am
@@ -25,7 +25,6 @@ libniepceui_a_SOURCES = \
        gridviewmodule.hpp gridviewmodule.cpp \
        moduleshell.hpp moduleshell.cpp \
        moduleshellwidget.hpp moduleshellwidget.cpp \
-       librarycellrenderer.hpp librarycellrenderer.cpp \
        imageliststore.hpp imageliststore.cpp\
        workspacecontroller.hpp workspacecontroller.cpp \
        metadatapanecontroller.hpp metadatapanecontroller.cpp \
diff --git a/src/niepce/ui/dialogs/importdialog.hpp b/src/niepce/ui/dialogs/importdialog.hpp
index 7452ed5..c66bd79 100644
--- a/src/niepce/ui/dialogs/importdialog.hpp
+++ b/src/niepce/ui/dialogs/importdialog.hpp
@@ -32,7 +32,6 @@
 #include "fwk/toolkit/gtkutils.hpp"
 #include "fwk/toolkit/dialog.hpp"
 #include "fwk/toolkit/uiresult.hpp"
-#include "imageliststore.hpp"
 #include "metadatapanecontroller.hpp"
 #include "importers/iimporterui.hpp"
 
diff --git a/src/niepce/ui/filmstripcontroller.cpp b/src/niepce/ui/filmstripcontroller.cpp
index 116883e..118c420 100644
--- a/src/niepce/ui/filmstripcontroller.cpp
+++ b/src/niepce/ui/filmstripcontroller.cpp
@@ -29,7 +29,7 @@
 
 namespace ui {
 
-FilmStripController::FilmStripController(const Glib::RefPtr<ImageListStore> & store,
+FilmStripController::FilmStripController(const ImageListStorePtr& store,
                                          const libraryclient::UIDataProviderWeakPtr& ui_data_provider)
     : m_ui_data_provider(ui_data_provider)
     , m_store(store)
@@ -42,7 +42,7 @@ Gtk::Widget * FilmStripController::buildWidget()
         return m_widget;
     }
     DBG_ASSERT(static_cast<bool>(m_store), "m_store NULL");
-    m_thumbview = manage(new ThumbStripView(m_store, m_ui_data_provider));
+    m_thumbview = manage(new ThumbStripView(m_store));
     GtkWidget *thn = ffi::npc_thumb_nav_new(m_thumbview->gobj(),
                                             ffi::ThumbNavMode::OneRow, true);
     m_thumbview->set_selection_mode(Gtk::SELECTION_SINGLE);
diff --git a/src/niepce/ui/filmstripcontroller.hpp b/src/niepce/ui/filmstripcontroller.hpp
index d46775d..0f4a62f 100644
--- a/src/niepce/ui/filmstripcontroller.hpp
+++ b/src/niepce/ui/filmstripcontroller.hpp
@@ -38,7 +38,7 @@ public:
        typedef std::weak_ptr<FilmStripController> WeakPtr;
 
        FilmStripController(
-          const Glib::RefPtr<ImageListStore>& store,
+          const ImageListStorePtr& store,
           const libraryclient::UIDataProviderWeakPtr& ui_data_provider);
 
        virtual Gtk::IconView * image_list() override;
@@ -50,7 +50,7 @@ public:
 private:
        libraryclient::UIDataProviderWeakPtr m_ui_data_provider;
        Gtk::IconView * m_thumbview;
-       Glib::RefPtr<ImageListStore> m_store;
+       ImageListStorePtr m_store;
 };
 
 
diff --git a/src/niepce/ui/gridviewmodule.cpp b/src/niepce/ui/gridviewmodule.cpp
index bc3a200..174a8f7 100644
--- a/src/niepce/ui/gridviewmodule.cpp
+++ b/src/niepce/ui/gridviewmodule.cpp
@@ -33,12 +33,11 @@
 #include "libraryclient/uidataprovider.hpp"
 #include "gridviewmodule.hpp"
 #include "moduleshell.hpp"
-#include "librarycellrenderer.hpp"
 
 namespace ui {
 
 GridViewModule::GridViewModule(const IModuleShell & shell,
-                               const Glib::RefPtr<ImageListStore> & store)
+                               const ImageListStorePtr& store)
   : m_shell(shell)
   , m_model(store)
   , m_librarylistview(nullptr)
@@ -88,13 +87,37 @@ void GridViewModule::display_none()
     m_metapanecontroller->display(0, nullptr);
 }
 
+bool GridViewModule::get_colour_callback_c(int32_t label, ffi::RgbColour* out,
+                                           const void* user_data)
+{
+    if (user_data == nullptr) {
+        return false;
+    }
+    return static_cast<const GridViewModule*>(user_data)->get_colour_callback(label, out);
+}
+
+bool GridViewModule::get_colour_callback(int32_t label, ffi::RgbColour* out) const
+{
+    libraryclient::UIDataProviderWeakPtr ui_data_provider(m_shell.get_ui_data_provider());
+    auto provider = ui_data_provider.lock();
+    DBG_ASSERT(static_cast<bool>(provider), "couldn't lock UI provider");
+    if (provider) {
+        auto c = provider->colourForLabel(label);
+        if (c.ok() && out) {
+            *out = c.unwrap();
+            return true;
+        }
+    }
+    return false;
+}
+
 Gtk::Widget * GridViewModule::buildWidget()
 {
   if(m_widget) {
     return m_widget;
   }
   m_widget = &m_lib_splitview;
-  m_librarylistview = Gtk::manage(new fwk::ImageGridView(m_model));
+  m_librarylistview = Gtk::manage(new fwk::ImageGridView(m_model->gobjmm()));
   m_librarylistview->set_selection_mode(Gtk::SELECTION_SINGLE);
   m_librarylistview->property_row_spacing() = 0;
   m_librarylistview->property_column_spacing() = 0;
@@ -111,33 +134,20 @@ Gtk::Widget * GridViewModule::buildWidget()
       .connect(sigc::mem_fun(*this, &GridViewModule::on_popup_menu));
 
   // the main cell
-  libraryclient::UIDataProviderWeakPtr ui_data_provider(m_shell.get_ui_data_provider());
-  LibraryCellRenderer* libcell = Gtk::manage(
-      new LibraryCellRenderer(
-          [ui_data_provider] (int32_t label, ffi::RgbColour* out) {
-              auto provider = ui_data_provider.lock();
-              DBG_ASSERT(static_cast<bool>(provider), "couldn't lock UI provider");
-              if (provider) {
-                  auto c = provider->colourForLabel(label);
-                  if (c.ok() && out) {
-                      *out = c.unwrap();
-                      return true;
-                  }
-              }
-              return false;
-          })
-      );
-  libcell->signal_rating_changed.connect(
-      sigc::mem_fun(*this, &GridViewModule::on_rating_changed));
+  Gtk::CellRenderer* libcell = manage(
+      Glib::wrap(
+          ffi::npc_library_cell_renderer_new(&get_colour_callback_c, this)));
+  g_signal_connect(
+      libcell->gobj(), "rating-changed", G_CALLBACK(GridViewModule::on_rating_changed), this);
 
   Glib::RefPtr<Gtk::CellArea> cell_area = m_librarylistview->property_cell_area();
   cell_area->pack_start(*libcell, FALSE);
   cell_area->add_attribute(*libcell, "pixbuf",
-                           ImageListStore::Columns::THUMB_INDEX);
+                           static_cast<gint>(ffi::ColIndex::Thumb));
   cell_area->add_attribute(*libcell, "libfile",
-                           ImageListStore::Columns::FILE_INDEX);
+                           static_cast<gint>(ffi::ColIndex::File));
   cell_area->add_attribute(*libcell, "status",
-                           ImageListStore::Columns::FILE_STATUS_INDEX);
+                           static_cast<gint>(ffi::ColIndex::FileStatus));
 
   m_scrollview.add(*m_librarylistview);
   m_scrollview.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
@@ -214,9 +224,11 @@ void GridViewModule::on_metadata_changed(const fwk::PropertyBagPtr & props,
     m_shell.get_selection_controller()->set_properties(props, old);
 }
 
-void GridViewModule::on_rating_changed(int /*id*/, int rating)
+void GridViewModule::on_rating_changed(GtkCellRenderer*, eng::library_id_t /*id*/,
+                                       int32_t rating, gpointer user_data)
 {
-    m_shell.get_selection_controller()->set_rating(rating);
+    auto self = static_cast<GridViewModule*>(user_data);
+    self->m_shell.get_selection_controller()->set_rating(rating);
 }
 
 bool GridViewModule::on_popup_menu()
diff --git a/src/niepce/ui/gridviewmodule.hpp b/src/niepce/ui/gridviewmodule.hpp
index b1b30cc..4ed48d8 100644
--- a/src/niepce/ui/gridviewmodule.hpp
+++ b/src/niepce/ui/gridviewmodule.hpp
@@ -1,7 +1,7 @@
 /*
  * niepce - ui/gridviewmodule.hpp
  *
- * Copyright (C) 2009-2019 Hubert Figuière
+ * Copyright (C) 2009-2020 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
@@ -52,7 +52,7 @@ public:
   typedef std::shared_ptr<GridViewModule> Ptr;
 
   GridViewModule(const IModuleShell & shell,
-                 const Glib::RefPtr<ImageListStore> & store);
+                 const ImageListStorePtr& store);
   virtual ~GridViewModule();
 
   void on_lib_notification(const eng::LibNotification &);
@@ -74,13 +74,16 @@ protected:
 
 
 private:
+  static bool get_colour_callback_c(int32_t label, ffi::RgbColour* out, const void* user_data);
+  bool get_colour_callback(int32_t label, ffi::RgbColour* out) const;
   void on_metadata_changed(const fwk::PropertyBagPtr&, const fwk::PropertyBagPtr& old);
-  void on_rating_changed(int id, int rating);
+  static void on_rating_changed(GtkCellRenderer*, eng::library_id_t id, int rating,
+                                gpointer user_data);
   bool on_popup_menu();
   bool on_librarylistview_click(GdkEventButton *e);
 
   const IModuleShell &               m_shell;
-  Glib::RefPtr<ImageListStore> m_model;
+  ImageListStorePtr m_model;
 
   // library split view
   fwk::ImageGridView*          m_librarylistview;
diff --git a/src/niepce/ui/image_list_store.rs b/src/niepce/ui/image_list_store.rs
new file mode 100644
index 0000000..2b612b8
--- /dev/null
+++ b/src/niepce/ui/image_list_store.rs
@@ -0,0 +1,243 @@
+/*
+ * niepce - niepce/ui/image_list_store.rs
+ *
+ * Copyright (C) 2020 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::ptr;
+
+use gdk_pixbuf;
+use gdk_pixbuf_sys;
+use glib::translate::*;
+use gtk;
+use gtk::prelude::*;
+use gtk::subclass::prelude::*;
+use gtk_sys;
+
+use npc_engine::db::libfile::{FileStatus, LibFile};
+use npc_engine::db::LibraryId;
+use npc_engine::library::notification::MetadataChange;
+use npc_fwk::PropertyValue;
+
+/// Wrap a libfile into something that can be in a glib::Value
+#[derive(Clone)]
+pub struct StoreLibFile(pub LibFile);
+
+impl glib::subclass::boxed::BoxedType for StoreLibFile {
+    const NAME: &'static str = "StoreLibFile";
+
+    glib_boxed_type!();
+}
+glib_boxed_derive_traits!(StoreLibFile);
+
+#[repr(i32)]
+pub enum ColIndex {
+    Thumb = 0,
+    File = 1,
+    StripThumb = 2,
+    FileStatus = 3,
+}
+
+pub struct ImageListStore {
+    store: gtk::ListStore,
+}
+
+impl ImageListStore {
+    pub fn new() -> Self {
+        let col_types: [glib::Type; 4] = [
+            gdk_pixbuf::Pixbuf::static_type(),
+            StoreLibFile::get_type(),
+            gdk_pixbuf::Pixbuf::static_type(),
+            glib::Type::I32,
+        ];
+
+        let store = gtk::ListStore::new(&col_types);
+
+        Self { store }
+    }
+
+    pub fn get_file_id_at_path(&self, path: &gtk::TreePath) -> LibraryId {
+        if let Some(iter) = self.store.get_iter(&path) {
+            if let Ok(libfile) = self
+                .store
+                .get_value(&iter, ColIndex::File as i32)
+                .get_some::<&StoreLibFile>()
+            {
+                return libfile.0.id();
+            }
+        }
+        0
+    }
+
+    pub fn get_file(&self, iter: &gtk::TreeIter) -> Option<LibFile> {
+        if let Ok(libfile) = self
+            .store
+            .get_value(&iter, ColIndex::File as i32)
+            .get_some::<&StoreLibFile>()
+        {
+            return Some(libfile.0.clone());
+        }
+        None
+    }
+
+    pub fn add_row(
+        &mut self,
+        thumb: &gdk_pixbuf::Pixbuf,
+        file: &LibFile,
+        strip_thumb: &gdk_pixbuf::Pixbuf,
+        status: FileStatus,
+    ) -> gtk::TreeIter {
+        let iter = self.store.append();
+        let store_libfile = StoreLibFile(file.clone());
+        let indices: [u32; 4] = [
+            ColIndex::Thumb as u32,
+            ColIndex::File as u32,
+            ColIndex::StripThumb as u32,
+            ColIndex::FileStatus as u32,
+        ];
+        assert!(thumb.ref_count() > 0);
+        assert!(strip_thumb.ref_count() > 0);
+        self.store.set(
+            &iter,
+            &indices,
+            &[thumb, &store_libfile, strip_thumb, &(status as i32)],
+        );
+        iter
+    }
+
+    pub fn set_thumbnail(
+        &mut self,
+        iter: &gtk::TreeIter,
+        thumb: &gdk_pixbuf::Pixbuf,
+        strip_thumb: &gdk_pixbuf::Pixbuf,
+    ) {
+        let indices: [u32; 2] = [ColIndex::Thumb as u32, ColIndex::StripThumb as u32];
+        assert!(thumb.ref_count() > 0);
+        assert!(strip_thumb.ref_count() > 0);
+        self.store.set(iter, &indices, &[thumb, strip_thumb]);
+    }
+
+    pub fn set_property(&self, iter: &gtk::TreeIter, change: &MetadataChange) {
+        if let Ok(libfile) = self
+            .store
+            .get_value(&iter, ColIndex::File as i32)
+            .get_some::<&StoreLibFile>()
+        {
+            assert!(libfile.0.id() == change.id);
+            let meta = change.meta;
+            if let PropertyValue::Int(value) = change.value {
+                let mut file = libfile.0.clone();
+                file.set_property(meta, value);
+                self.store
+                    .set_value(&iter, ColIndex::File as u32, &StoreLibFile(file).to_value());
+            } else {
+                err_out!("Wrong property type");
+            }
+        }
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn npc_image_list_store_new() -> *mut ImageListStore {
+    let box_ = Box::new(ImageListStore::new());
+    Box::into_raw(box_)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn npc_image_list_store_delete(self_: *mut ImageListStore) {
+    assert!(!self_.is_null());
+    Box::from_raw(self_);
+}
+
+/// Return the gobj for the GtkListStore. You must ref it to hold it.
+#[no_mangle]
+pub unsafe extern "C" fn npc_image_list_store_gobj(
+    self_: &ImageListStore,
+) -> *mut gtk_sys::GtkListStore {
+    self_.store.to_glib_none().0
+}
+
+/// Return the ID of the file at the given GtkTreePath
+#[no_mangle]
+pub unsafe extern "C" fn npc_image_list_store_get_file_id_at_path(
+    self_: &ImageListStore,
+    path: *const gtk_sys::GtkTreePath,
+) -> LibraryId {
+    assert!(!path.is_null());
+    self_.get_file_id_at_path(&from_glib_borrow(path))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn npc_image_list_store_add_row(
+    self_: &mut ImageListStore,
+    thumb: *mut gdk_pixbuf_sys::GdkPixbuf,
+    file: *const LibFile,
+    strip_thumb: *mut gdk_pixbuf_sys::GdkPixbuf,
+    status: FileStatus,
+) -> gtk_sys::GtkTreeIter {
+    assert!(!thumb.is_null());
+    assert!(!strip_thumb.is_null());
+    *self_
+        .add_row(
+            &from_glib_borrow(thumb),
+            &*file,
+            &from_glib_borrow(strip_thumb),
+            status,
+        )
+        .to_glib_none()
+        .0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn npc_image_list_store_set_tnail(
+    self_: &mut ImageListStore,
+    iter: *mut gtk_sys::GtkTreeIter,
+    thumb: *mut gdk_pixbuf_sys::GdkPixbuf,
+    strip_thumb: *mut gdk_pixbuf_sys::GdkPixbuf,
+) {
+    assert!(!iter.is_null());
+    assert!(!thumb.is_null());
+    assert!(!strip_thumb.is_null());
+    self_.set_thumbnail(
+        &from_glib_borrow(iter),
+        &from_glib_borrow(thumb),
+        &from_glib_borrow(strip_thumb),
+    )
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn npc_image_list_store_get_file(
+    self_: &mut ImageListStore,
+    iter: *mut gtk_sys::GtkTreeIter,
+) -> *mut LibFile {
+    assert!(!iter.is_null());
+    if let Some(libfile) = self_.get_file(&from_glib_borrow(iter)) {
+        Box::into_raw(Box::new(libfile))
+    } else {
+        ptr::null_mut()
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn npc_image_list_store_set_property(
+    self_: &mut ImageListStore,
+    iter: *const gtk_sys::GtkTreeIter,
+    change: *const MetadataChange,
+) {
+    assert!(!iter.is_null());
+    assert!(!change.is_null());
+    self_.set_property(&from_glib_borrow(mut_override(iter)), &*change);
+}
diff --git a/src/niepce/ui/imageliststore.cpp b/src/niepce/ui/imageliststore.cpp
index f854f37..800b7cc 100644
--- a/src/niepce/ui/imageliststore.cpp
+++ b/src/niepce/ui/imageliststore.cpp
@@ -56,24 +56,28 @@ Glib::RefPtr<Gdk::Pixbuf> ImageListStore::get_loading_icon()
     return icon;
 }
 
-Glib::RefPtr<ImageListStore> ImageListStore::create()
+ImageListStorePtr ImageListStore::create()
 {
-    static const Columns columns;
-    return Glib::RefPtr<ImageListStore>(new ImageListStore(columns));
+    return std::make_shared<ImageListStore>(ffi::npc_image_list_store_new());
 }
 
-ImageListStore::ImageListStore(const Columns& _columns)
-    : Gtk::ListStore(_columns)
-    , m_columns(_columns)
+ImageListStore::ImageListStore(ffi::ImageListStore* store)
+    : m_store(store)
+    , m_store_wrap(Glib::wrap(GTK_LIST_STORE(ffi::npc_image_list_store_gobj(store)), true))
     , m_current_folder(0)
     , m_current_keyword(0)
 {
 }
 
+ImageListStore::~ImageListStore()
+{
+    m_store_wrap.reset();
+    ffi::npc_image_list_store_delete(m_store);
+}
 
 Gtk::TreeIter ImageListStore::get_iter_from_id(eng::library_id_t id) const
 {
-    auto iter = m_idmap.find( id );
+    auto iter = m_idmap.find(id);
     if(iter != m_idmap.end()) {
         return iter->second;
     }
@@ -84,48 +88,45 @@ Gtk::TreePath ImageListStore::get_path_from_id(eng::library_id_t id) const
 {
     Gtk::TreeIter iter = get_iter_from_id(id);
     if(iter) {
-        return get_path(iter);
+        return m_store_wrap->get_path(iter);
     }
     return Gtk::TreePath();
 }
 
-eng::library_id_t ImageListStore::get_libfile_id_at_path(const Gtk::TreePath& path)
+eng::library_id_t ImageListStore::get_libfile_id_at_path(const Gtk::TreePath &path) const
 {
-    auto iter = get_iter(path);
-    eng::LibFilePtr libfile = (*iter)[m_columns.m_libfile];
-    if (libfile) {
-        return engine_db_libfile_id(libfile.get());
-    }
-    return 0;
+    return ffi::npc_image_list_store_get_file_id_at_path(m_store, path.gobj());
 }
 
 eng::LibFilePtr ImageListStore::get_file(eng::library_id_t id) const
 {
     auto iter = get_iter_from_id(id);
     if (iter) {
-        return (*iter)[m_columns.m_libfile];
+        auto f = ffi::npc_image_list_store_get_file(m_store, iter.gobj());
+        if (f) {
+            return eng::libfile_wrap(f);
+        }
     }
     return eng::LibFilePtr();
 }
 
 void ImageListStore::add_libfile(const eng::LibFilePtr & f)
 {
-    Gtk::TreeModel::iterator riter = append();
-    Gtk::TreeRow row = *riter;
     Glib::RefPtr<Gdk::Pixbuf> icon = get_loading_icon();
-    row[m_columns.m_pix] = icon;
-    row[m_columns.m_libfile] = f;
-    row[m_columns.m_strip_thumb]
-        = fwk::gdkpixbuf_scale_to_fit(icon, 100);
-    row[m_columns.m_file_status] = static_cast<gint>(eng::FileStatus::Ok);
-    m_idmap[engine_db_libfile_id(f.get())] = riter;
+    DBG_ASSERT(static_cast<bool>(f), "f can't be null");
+    auto iter = ffi::npc_image_list_store_add_row(m_store,
+        icon->gobj(), f.get(), fwk::gdkpixbuf_scale_to_fit(icon, 100)->gobj(),
+        eng::FileStatus::Ok);
+
+    m_idmap[engine_db_libfile_id(f.get())] = Gtk::TreeIter(
+        GTK_TREE_MODEL(m_store_wrap->gobj()), &iter);
 }
 
 void ImageListStore::clear_content()
 {
     // clear the map before the list.
     m_idmap.clear();
-    clear();
+    m_store_wrap->clear();
 }
 
 void ImageListStore::on_lib_notification(const eng::LibNotification &ln)
@@ -167,7 +168,7 @@ void ImageListStore::on_lib_notification(const eng::LibNotification &ln)
             DBG_OUT("from this folder");
             auto iter = get_iter_from_id(param->file);
             if (iter) {
-                iter = erase(iter);
+                iter = m_store_wrap->erase(iter);
             }
         } else if (param->to == m_current_folder) {
             // XXX add to list. but this isn't likely to happen atm.
@@ -194,14 +195,8 @@ void ImageListStore::on_lib_notification(const eng::LibNotification &ln)
         if(is_property_interesting(prop)) {
             std::map<eng::library_id_t, Gtk::TreeIter>::const_iterator iter =
                 m_idmap.find(ffi::metadatachange_get_id(m));
-            if(iter != m_idmap.end()) {
-                Gtk::TreeRow row = *(iter->second);
-                //
-                eng::LibFilePtr file = row[m_columns.m_libfile];
-                engine_db_libfile_set_property(
-                    file.get(), prop, fwk_property_value_get_integer(
-                        ffi::metadatachange_get_value(m)));
-                row[m_columns.m_libfile] = file;
+            if (iter != m_idmap.end()) {
+                ffi::npc_image_list_store_set_property(m_store, iter->second.gobj(), m);
             }
         }
         break;
@@ -235,9 +230,9 @@ void ImageListStore::on_tnail_notification(const eng::ThumbnailNotification &tn)
     if(iter != m_idmap.end()) {
         // found the icon view item
         auto pixbuf = tn.pixmap.pixbuf();
-        Gtk::TreeRow row = *(iter->second);
-        row[m_columns.m_pix] = pixbuf;
-        row[m_columns.m_strip_thumb] = fwk::gdkpixbuf_scale_to_fit(pixbuf, 100);
+        ffi::npc_image_list_store_set_tnail(
+            m_store, iter->second.gobj(), pixbuf->gobj(),
+            fwk::gdkpixbuf_scale_to_fit(pixbuf, 100)->gobj());
     }
     else {
         DBG_OUT("row %Ld not found", (long long)tn.id);
diff --git a/src/niepce/ui/imageliststore.hpp b/src/niepce/ui/imageliststore.hpp
index a0ceebb..0276f1f 100644
--- a/src/niepce/ui/imageliststore.hpp
+++ b/src/niepce/ui/imageliststore.hpp
@@ -1,7 +1,7 @@
 /*
  * niepce - ui/imageliststore.h
  *
- * Copyright (C) 2008-2018 Hubert Figuiere
+ * Copyright (C) 2008-2020 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
@@ -17,11 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-
-
-#ifndef __UI_IMAGELISTSTORE__
-#define __UI_IMAGELISTSTORE__
-
+#pragma once
 
 #include <gdkmm/pixbuf.h>
 #include <gtkmm/liststore.h>
@@ -34,42 +30,43 @@
 
 namespace ui {
 
-/** @brief the general list store */
+class ImageListStore;
+
+typedef std::shared_ptr<ImageListStore> ImageListStorePtr;
+
+/** @brief the general list store. Wraps the list store from Rust. */
 class ImageListStore
-    : public Gtk::ListStore
 {
 public:
     class Columns
         : public Gtk::TreeModelColumnRecord
     {
     public:
-        enum {
-            THUMB_INDEX = 0,
-            FILE_INDEX = 1,
-            STRIP_THUMB_INDEX = 2,
-            FILE_STATUS_INDEX = 3
-        };
         Columns()
             {
                 add(m_pix);
-                add(m_libfile);
+                add(m_libfile_do_not_use);
                 add(m_strip_thumb);
                 add(m_file_status);
             }
         Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > m_pix;
-        Gtk::TreeModelColumn<eng::LibFilePtr> m_libfile;
+        Gtk::TreeModelColumn<eng::LibFilePtr> m_libfile_do_not_use;
         Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > m_strip_thumb;
         Gtk::TreeModelColumn<gint> m_file_status;
     };
 
+    ImageListStore(ffi::ImageListStore*);
+    ~ImageListStore();
+    Glib::RefPtr<Gtk::ListStore> gobjmm() const
+        { return m_store_wrap; }
     Gtk::TreePath get_path_from_id(eng::library_id_t id) const;
     Gtk::TreeIter get_iter_from_id(eng::library_id_t id) const;
-    eng::library_id_t get_libfile_id_at_path(const Gtk::TreePath& path);
+    eng::library_id_t get_libfile_id_at_path(const Gtk::TreePath& path) const;
     eng::LibFilePtr get_file(eng::library_id_t id) const;
     size_t get_count() const
-        { return children().size(); }
+        { return m_store_wrap->children().size(); }
 
-    static Glib::RefPtr<ImageListStore> create();
+    static ImageListStorePtr create();
 
     void set_parent_controller(const fwk::Controller::WeakPtr & ctrl)
         { m_controller = ctrl; }
@@ -78,8 +75,7 @@ public:
     void clear_content();
     void on_lib_notification(const eng::LibNotification &n);
     void on_tnail_notification(const eng::ThumbnailNotification &n);
-protected:
-    ImageListStore(const Columns& columns);
+
 private:
     /// Add the LibFile to the model
     void add_libfile(const eng::LibFilePtr & f);
@@ -88,7 +84,9 @@ private:
     libraryclient::LibraryClientPtr getLibraryClient();
     static bool is_property_interesting(fwk::PropertyIndex idx);
 
-    const Columns           & m_columns;
+    Columns m_columns;
+    ffi::ImageListStore* m_store;
+    Glib::RefPtr<Gtk::ListStore> m_store_wrap;
     eng::library_id_t m_current_folder;
     eng::library_id_t m_current_keyword;
     std::map<eng::library_id_t, Gtk::TreeIter> m_idmap;
@@ -96,7 +94,6 @@ private:
 };
 
 }
-
 /*
   Local Variables:
   mode:c++
@@ -107,4 +104,3 @@ private:
   End:
 */
 
-#endif
diff --git a/src/niepce/ui/library_cell_renderer.rs b/src/niepce/ui/library_cell_renderer.rs
index b4d5f7d..e4b3471 100644
--- a/src/niepce/ui/library_cell_renderer.rs
+++ b/src/niepce/ui/library_cell_renderer.rs
@@ -17,8 +17,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+use libc::c_void;
 use once_cell::unsync::Lazy;
 use std::cell::{Cell, RefCell};
+use std::ptr;
 
 use cairo;
 use gdk;
@@ -33,7 +35,8 @@ use gtk::prelude::*;
 use gtk::subclass::prelude::*;
 use gtk::CellRendererPixbufClass;
 
-use npc_engine::db::libfile::{FileStatus, FileType, LibFile};
+use crate::niepce::ui::image_list_store::StoreLibFile;
+use npc_engine::db::libfile::{FileStatus, FileType};
 use npc_fwk::base::rgbcolour::RgbColour;
 use npc_fwk::toolkit::clickable_cell_renderer::ClickableCellRenderer;
 use npc_fwk::toolkit::widgets::rating_label::RatingLabel;
@@ -78,7 +81,10 @@ glib_wrapper! {
 }
 
 impl LibraryCellRenderer {
-    pub fn new(callback: Option<GetColourCallback>) -> Self {
+    /// Create a library cell renderer.
+    /// callback: an optional callback used to get a colour for labels.
+    /// callback_data: raw pointer passed as is to the callback.
+    pub fn new(callback: Option<GetColourCallback>, callback_data: *const c_void) -> Self {
         let obj: Self = glib::Object::new(
             Self::static_type(),
             &[("mode", &gtk::CellRendererMode::Activatable)],
@@ -87,11 +93,80 @@ impl LibraryCellRenderer {
         .downcast()
         .expect("Created Library Cell Renderer is of wrong type");
 
-        let priv_ = LibraryCellRendererPriv::from_instance(&obj);
-        priv_.get_colour_callback.replace(callback);
+        if callback.is_some() {
+            let priv_ = LibraryCellRendererPriv::from_instance(&obj);
+            priv_.get_colour_callback.replace(callback);
+            priv_.callback_data.set(callback_data);
+        }
 
         obj
     }
+
+    /// Create a new thumb renderer, basicall a LibraryCellRender with some options.
+    /// Mostly just draw the thumbnail.
+    /// Doesn't need the get_colour_callback
+    pub fn new_thumb_renderer() -> Self {
+        let cell_renderer = Self::new(None, ptr::null());
+
+        cell_renderer.set_pad(0);
+        cell_renderer.set_size(100);
+        cell_renderer.set_drawborder(false);
+        cell_renderer.set_drawemblem(false);
+        cell_renderer.set_drawrating(false);
+        cell_renderer.set_drawlabel(false);
+        cell_renderer.set_drawflag(false);
+
+        cell_renderer
+    }
+}
+
+/// Option to set for the LibraryCellRenderer
+pub trait LibraryCellRendererExt {
+    /// Set padding
+    fn set_pad(&self, pad: i32);
+    /// Set size
+    fn set_size(&self, size: i32);
+    /// Whether to draw the border
+    fn set_drawborder(&self, draw: bool);
+    /// Whether to draw the emblem
+    fn set_drawemblem(&self, draw: bool);
+    /// Whether to draw the rating
+    fn set_drawrating(&self, draw: bool);
+    /// Whether to draw the label
+    fn set_drawlabel(&self, draw: bool);
+    /// Whether to draw the flag
+    fn set_drawflag(&self, draw: bool);
+}
+
+impl LibraryCellRendererExt for LibraryCellRenderer {
+    fn set_pad(&self, pad: i32) {
+        let priv_ = LibraryCellRendererPriv::from_instance(self);
+        priv_.pad.set(pad);
+    }
+    fn set_size(&self, size: i32) {
+        let priv_ = LibraryCellRendererPriv::from_instance(self);
+        priv_.size.set(size);
+    }
+    fn set_drawborder(&self, draw: bool) {
+        let priv_ = LibraryCellRendererPriv::from_instance(self);
+        priv_.drawborder.set(draw);
+    }
+    fn set_drawemblem(&self, draw: bool) {
+        let priv_ = LibraryCellRendererPriv::from_instance(self);
+        priv_.draw_emblem.set(draw);
+    }
+    fn set_drawrating(&self, draw: bool) {
+        let priv_ = LibraryCellRendererPriv::from_instance(self);
+        priv_.draw_rating.set(draw);
+    }
+    fn set_drawlabel(&self, draw: bool) {
+        let priv_ = LibraryCellRendererPriv::from_instance(self);
+        priv_.draw_label.set(draw);
+    }
+    fn set_drawflag(&self, draw: bool) {
+        let priv_ = LibraryCellRendererPriv::from_instance(self);
+        priv_.draw_flag.set(draw);
+    }
 }
 
 #[derive(Default)]
@@ -130,21 +205,12 @@ impl ClickableCellRenderer for LibraryCellRenderer {
     }
 }
 
-/// Wrap a libfile into something that can be in a glib::Value
-#[derive(Clone)]
-struct CellLibFile(LibFile);
-
-impl glib::subclass::boxed::BoxedType for CellLibFile {
-    const NAME: &'static str = "CellLibFile";
-
-    glib_boxed_type!();
-}
-glib_boxed_derive_traits!(CellLibFile);
-
-type GetColourCallback = unsafe extern "C" fn(i32, *mut RgbColour) -> bool;
+/// Callback type to get the label colour.
+/// Return false if none is returned.
+type GetColourCallback = unsafe extern "C" fn(i32, *mut RgbColour, *const c_void) -> bool;
 
 pub struct LibraryCellRendererPriv {
-    libfile: RefCell<Option<CellLibFile>>,
+    libfile: RefCell<Option<StoreLibFile>>,
     status: Cell<FileStatus>,
     size: Cell<i32>,
     pad: Cell<i32>,
@@ -156,6 +222,7 @@ pub struct LibraryCellRendererPriv {
     draw_status: Cell<bool>,
     clickable_cell: RefCell<ClickableCell>,
     get_colour_callback: RefCell<Option<GetColourCallback>>,
+    callback_data: Cell<*const c_void>,
 }
 
 impl LibraryCellRendererPriv {
@@ -163,7 +230,7 @@ impl LibraryCellRendererPriv {
         self.status.set(status);
     }
 
-    fn set_libfile(&self, libfile: Option<CellLibFile>) {
+    fn set_libfile(&self, libfile: Option<StoreLibFile>) {
         self.libfile.replace(libfile);
     }
 
@@ -239,7 +306,7 @@ impl LibraryCellRendererPriv {
         if let Some(f) = *self.get_colour_callback.borrow() {
             unsafe {
                 let mut c = RgbColour::default();
-                if f(label_id, &mut c) {
+                if f(label_id, &mut c, self.callback_data.get()) {
                     return Some(c);
                 }
             }
@@ -254,7 +321,7 @@ static PROPERTIES: [subclass::Property; 2] = [
             libfile,
             "Library File",
             "File from the library in the cell",
-            CellLibFile::get_type(),
+            StoreLibFile::get_type(),
             glib::ParamFlags::READWRITE,
         )
     }),
@@ -284,7 +351,7 @@ impl ObjectSubclass for LibraryCellRendererPriv {
         klass.add_signal(
             "rating-changed",
             glib::SignalFlags::RUN_LAST,
-            &[Type::U64, Type::I32],
+            &[Type::I64, Type::I32],
             Type::Unit,
         );
     }
@@ -303,6 +370,7 @@ impl ObjectSubclass for LibraryCellRendererPriv {
             draw_status: Cell::new(true),
             clickable_cell: RefCell::new(ClickableCell::default()),
             get_colour_callback: RefCell::new(None),
+            callback_data: Cell::new(ptr::null()),
         }
     }
 }
@@ -319,7 +387,7 @@ impl ObjectImpl for LibraryCellRendererPriv {
         match *prop {
             subclass::Property("libfile", ..) => {
                 let libfile = value
-                    .get::<&CellLibFile>()
+                    .get::<&StoreLibFile>()
                     .expect("type conformity checked by `Object::set_property`")
                     .map(|f| f.clone());
                 self.set_libfile(libfile);
@@ -556,12 +624,32 @@ unsafe impl<T: ObjectSubclass + LibraryCellRendererImpl> IsSubclassable<T>
     }
 }
 
-// XXX we must pass the get_colour callback
 #[no_mangle]
 pub unsafe extern "C" fn npc_library_cell_renderer_new(
-    get_colour: Option<unsafe extern "C" fn(i32, *mut RgbColour) -> bool>,
+    get_colour: Option<unsafe extern "C" fn(i32, *mut RgbColour, *const c_void) -> bool>,
+    callback_data: *const c_void,
 ) -> *mut gtk_sys::GtkCellRenderer {
-    LibraryCellRenderer::new(get_colour)
+    LibraryCellRenderer::new(get_colour, callback_data)
+        .upcast::<gtk::CellRenderer>()
+        .to_glib_full()
+}
+
+/// Hit test for the cellrenderer.
+#[no_mangle]
+pub unsafe extern "C" fn npc_library_cell_renderer_hit(
+    ptr: *mut gtk_sys::GtkCellRenderer,
+    x: i32,
+    y: i32,
+) {
+    let mut renderer = gtk::CellRenderer::from_glib_borrow(ptr)
+        .downcast::<LibraryCellRenderer>()
+        .expect("Expected a LibraryCellRenderer");
+    renderer.hit(x, y);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn npc_library_thumb_cell_renderer_new() -> *mut gtk_sys::GtkCellRenderer {
+    LibraryCellRenderer::new_thumb_renderer()
         .upcast::<gtk::CellRenderer>()
         .to_glib_full()
 }
diff --git a/src/niepce/ui/mod.rs b/src/niepce/ui/mod.rs
index ec86fe3..9e19cbb 100644
--- a/src/niepce/ui/mod.rs
+++ b/src/niepce/ui/mod.rs
@@ -18,6 +18,7 @@
  */
 
 pub mod dialogs;
+pub mod image_list_store;
 pub mod imagetoolbar;
 pub mod library_cell_renderer;
 pub mod thumb_nav;
diff --git a/src/niepce/ui/moduleshell.hpp b/src/niepce/ui/moduleshell.hpp
index a61d545..1e9d6ce 100644
--- a/src/niepce/ui/moduleshell.hpp
+++ b/src/niepce/ui/moduleshell.hpp
@@ -62,7 +62,7 @@ public:
         {
             return m_mapm;
         }
-    const Glib::RefPtr<ImageListStore> & get_list_store() const
+    const ImageListStorePtr& get_list_store() const
         {
             return m_selection_controller->get_list_store();
         }
diff --git a/src/niepce/ui/niepcewindow.cpp b/src/niepce/ui/niepcewindow.cpp
index 0a972f0..d8973cc 100644
--- a/src/niepce/ui/niepcewindow.cpp
+++ b/src/niepce/ui/niepcewindow.cpp
@@ -121,7 +121,7 @@ NiepceWindow::_createModuleShell()
                      &GridViewModule::on_lib_notification));
     m_notifcenter->signal_lib_notification
         .connect(sigc::mem_fun(
-                     *get_pointer(m_moduleshell->get_list_store()),
+                     m_moduleshell->get_list_store().get(),
                      &ImageListStore::on_lib_notification));
     m_notifcenter->signal_lib_notification
         .connect(sigc::mem_fun(
@@ -129,7 +129,7 @@ NiepceWindow::_createModuleShell()
                      &mapm::MapModule::on_lib_notification));
     m_notifcenter->signal_thumbnail_notification
         .connect(sigc::mem_fun(
-                     *get_pointer(m_moduleshell->get_list_store()),
+                     m_moduleshell->get_list_store().get(),
                      &ImageListStore::on_tnail_notification));
 
 
diff --git a/src/niepce/ui/selectioncontroller.cpp b/src/niepce/ui/selectioncontroller.cpp
index 46c668f..3624aa9 100644
--- a/src/niepce/ui/selectioncontroller.cpp
+++ b/src/niepce/ui/selectioncontroller.cpp
@@ -66,7 +66,7 @@ void SelectionController::activated(const Gtk::TreeModel::Path & path,
                                     const IImageSelectable::WeakPtr & /*selectable*/)
 {
     fwk::AutoFlag f(m_in_handler);
-    eng::library_id_t selection = m_imageliststore->get_libfile_id_at_path(path);
+    auto selection = m_imageliststore->get_libfile_id_at_path(path);
     if (selection) {
         DBG_OUT("item activated %Ld", (long long)selection);
         signal_activated(selection);
@@ -131,7 +131,7 @@ void SelectionController::_selection_move(bool backwards)
     }
 
     if(backwards) {
-        if(iter != m_imageliststore->children().begin()) {
+        if(iter != m_imageliststore->gobjmm()->children().begin()) {
             --iter;
         }
     }
diff --git a/src/niepce/ui/selectioncontroller.hpp b/src/niepce/ui/selectioncontroller.hpp
index c5cb994..09ee4da 100644
--- a/src/niepce/ui/selectioncontroller.hpp
+++ b/src/niepce/ui/selectioncontroller.hpp
@@ -72,7 +72,7 @@ public:
     void selected(const IImageSelectable::WeakPtr &);
 
 
-    const Glib::RefPtr<ImageListStore> & get_list_store() const
+    const ImageListStorePtr& get_list_store() const
         { return m_imageliststore; }
 
     // the signal to call when selection is changed.
@@ -129,7 +129,7 @@ private:
      */
     void _selection_move(bool backwards);
 
-    Glib::RefPtr<ImageListStore>  m_imageliststore;
+    ImageListStorePtr  m_imageliststore;
     bool m_in_handler;
     std::vector<IImageSelectable::WeakPtr> m_selectables;
 };
diff --git a/src/niepce/ui/thumbstripview.cpp b/src/niepce/ui/thumbstripview.cpp
index 3129d87..0131efc 100644
--- a/src/niepce/ui/thumbstripview.cpp
+++ b/src/niepce/ui/thumbstripview.cpp
@@ -32,7 +32,6 @@
 #include "fwk/utils/boost.hpp"
 #include "engine/db/libfile.hpp"
 #include "thumbstripview.hpp"
-#include "librarycellrenderer.hpp"
 
 #include <gdkmm/general.h>
 
@@ -55,65 +54,33 @@ static GtkTargetEntry target_table[] = {
 };
 #endif
 
-class ThumbStripCell
-    : public LibraryCellRenderer
-{
-public:
-    ThumbStripCell(const GetColourFunc& get_colour);
-};
-
-ThumbStripCell::ThumbStripCell(const GetColourFunc& get_colour)
-    : Glib::ObjectBase(typeid(ThumbStripCell))
-    , LibraryCellRenderer(get_colour)
-{
-    set_pad(0);
-    set_size(100);
-    set_drawborder(false);
-    set_drawemblem(false);
-    set_drawrating(false);
-    set_drawlabel(false);
-    set_drawflag(false);
-}
-
-ThumbStripView::ThumbStripView(const Glib::RefPtr<ui::ImageListStore> & store,
-                               const libraryclient::UIDataProviderWeakPtr& ui_data_provider)
+ThumbStripView::ThumbStripView(const ui::ImageListStorePtr& store)
     : Glib::ObjectBase(typeid(ThumbStripView))
-    , Gtk::IconView(Glib::RefPtr<Gtk::TreeModel>::cast_dynamic(store))
+    , Gtk::IconView(Glib::RefPtr<Gtk::TreeModel>::cast_dynamic(store->gobjmm()))
     , property_item_height(*this, "item-height", 100)
     , m_store(store)
     , m_model_item_count(0)
 {
-    m_renderer = manage(
-        new ThumbStripCell(
-            [ui_data_provider] (int32_t label, ffi::RgbColour* out) {
-                auto provider = ui_data_provider.lock();
-                DBG_ASSERT(static_cast<bool>(provider), "couldn't lock UI provider");
-                if (provider) {
-                    auto c = provider->colourForLabel(label);
-                    if (c.ok() && out) {
-                        *out = c.unwrap();
-                        return true;
-                    }
-                }
-                return false;
-            })
-        );
+    auto r = ffi::npc_library_thumb_cell_renderer_new();
+    DBG_ASSERT(r, "Renderer is null");
+    m_renderer = manage(Glib::wrap(GTK_CELL_RENDERER_PIXBUF(r)));
 
     pack_start(*m_renderer, FALSE);
     connect_property_changed("item-height",
                              [this] () {
                                  m_renderer->property_height() = this->property_item_height;
                              });
+
     m_renderer->property_height() = 100;
     m_renderer->property_yalign() = 0.5;
     m_renderer->property_xalign() = 0.5;
 
     add_attribute(*m_renderer, "pixbuf",
-                  ui::ImageListStore::Columns::STRIP_THUMB_INDEX);
+                  static_cast<gint>(ffi::ColIndex::StripThumb));
     add_attribute(*m_renderer, "libfile",
-                  ui::ImageListStore::Columns::FILE_INDEX);
+                  static_cast<gint>(ffi::ColIndex::File));
     add_attribute(*m_renderer, "status",
-                  ui::ImageListStore::Columns::FILE_STATUS_INDEX);
+                  static_cast<gint>(ffi::ColIndex::FileStatus));
     set_selection_mode(Gtk::SELECTION_MULTIPLE);
     set_column_spacing(THUMB_STRIP_VIEW_SPACING);
 
@@ -128,14 +95,14 @@ ThumbStripView::ThumbStripView(const Glib::RefPtr<ui::ImageListStore> & store,
     setup_model(store);
 }
 
-void ThumbStripView::set_model(const Glib::RefPtr<ui::ImageListStore> & store)
+void ThumbStripView::set_model(const ui::ImageListStorePtr& store)
 {
     m_store = store;
     setup_model(store);
-    IconView::set_model(store);
+    IconView::set_model(store->gobjmm());
 }
 
-void ThumbStripView::setup_model(const Glib::RefPtr<ui::ImageListStore> & store)
+void ThumbStripView::setup_model(const ui::ImageListStorePtr& store)
 {
     m_model_add.disconnect();
     m_model_rm.disconnect();
@@ -143,13 +110,13 @@ void ThumbStripView::setup_model(const Glib::RefPtr<ui::ImageListStore> & store)
     m_model_item_count = m_store->get_count();
     update_item_count();
 
-    m_model_add = store->signal_row_inserted()
+    m_model_add = store->gobjmm()->signal_row_inserted()
         .connect(sigc::mem_fun(*this, &ThumbStripView::row_added));
-    m_model_rm = store->signal_row_deleted()
+    m_model_rm = store->gobjmm()->signal_row_deleted()
         .connect(sigc::mem_fun(*this, &ThumbStripView::row_deleted));
 }
 
-const Glib::RefPtr<ui::ImageListStore> & ThumbStripView::get_model() const
+const ui::ImageListStorePtr& ThumbStripView::get_model() const
 {
     return m_store;
 }
diff --git a/src/niepce/ui/thumbstripview.hpp b/src/niepce/ui/thumbstripview.hpp
index 0149927..588240b 100644
--- a/src/niepce/ui/thumbstripview.hpp
+++ b/src/niepce/ui/thumbstripview.hpp
@@ -1,7 +1,7 @@
 /*
  * niepce - niepce/ui/thumbstripview.hpp
  *
- * Copyright (C) 2009-2014 Hubert Figuiere
+ * Copyright (C) 2009-2020 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,8 +17,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef _THUMB_STRIP_VIEW_HPP_
-#define _THUMB_STRIP_VIEW_HPP_
+#pragma once
 
 #include <glibmm/property.h>
 
@@ -26,7 +25,6 @@
 #include <gtkmm/orientable.h>
 #include <gtkmm/cellrendererpixbuf.h>
 
-#include "libraryclient/uidataprovider.hpp"
 #include "niepce/ui/imageliststore.hpp"
 
 namespace ui {
@@ -35,11 +33,10 @@ class ThumbStripView
   : public Gtk::IconView
 {
 public:
-    ThumbStripView(const Glib::RefPtr<ui::ImageListStore>& store,
-                   const libraryclient::UIDataProviderWeakPtr& ui_data_provider);
+    ThumbStripView(const ImageListStorePtr& store);
 
-    void set_model(const Glib::RefPtr<ui::ImageListStore> & store);
-    const Glib::RefPtr<ui::ImageListStore> & get_model() const;
+    void set_model(const ui::ImageListStorePtr& store);
+    const ui::ImageListStorePtr& get_model() const;
     void set_item_height(int height);
 
     Glib::Property<gint> property_item_height;
@@ -48,14 +45,14 @@ private:
                           Gtk::SelectionData&,guint,guint) override;
     void update_visible_range(int, int);
 
-    void setup_model(const Glib::RefPtr<ui::ImageListStore> & store);
+    void setup_model(const ui::ImageListStorePtr& store);
     void row_added(const Gtk::TreeModel::Path&,
                    const Gtk::TreeModel::iterator&);
     void row_deleted(const Gtk::TreeModel::Path&);
     void update_item_count();
 
-    Glib::RefPtr<ui::ImageListStore> m_store;
-    Gtk::CellRendererPixbuf  *m_renderer;
+    ImageListStorePtr m_store;
+    Gtk::CellRendererPixbuf* m_renderer;
 
     int m_model_item_count;
     sigc::connection m_model_add;
@@ -64,8 +61,6 @@ private:
 
 
 }
-
-#endif
 /*
   Local Variables:
   mode:c++


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