[niepce] rust+ui: port the library cell renderer to Rust
- From: Hubert Figuière <hub src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [niepce] rust+ui: port the library cell renderer to Rust
- Date: Mon, 27 Jan 2020 05:43:28 +0000 (UTC)
commit 9c6853619786ed35a4fb1b3ca957793cae4ffedb
Author: Hubert Figuière <hub figuiere net>
Date: Mon Jan 27 00:42:44 2020 -0500
rust+ui: port the library cell renderer to Rust
- still not used
- tweak the model a bit to match
- Change the prototype of the get_colour callback
Cargo.lock | 3 +
Cargo.toml | 5 +-
build.rs | 1 +
crates/npc-engine/src/db/libfile.rs | 12 +
.../npc-fwk/src/toolkit/clickable_cell_renderer.rs | 28 +
crates/npc-fwk/src/toolkit/mod.rs | 2 +
src/Makefile.am | 1 +
src/lib.rs | 3 +
src/libraryclient/uidataprovider.cpp | 8 +-
src/libraryclient/uidataprovider.hpp | 2 +-
src/niepce/ui/gridviewmodule.cpp | 12 +-
src/niepce/ui/imageliststore.cpp | 4 +-
src/niepce/ui/imageliststore.hpp | 2 +-
src/niepce/ui/library_cell_renderer.rs | 567 +++++++++++++++++++++
src/niepce/ui/librarycellrenderer.cpp | 11 +-
src/niepce/ui/librarycellrenderer.hpp | 4 +-
src/niepce/ui/mod.rs | 1 +
src/niepce/ui/thumbstripview.cpp | 12 +-
18 files changed, 654 insertions(+), 24 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index 8bdeb08..9131555 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -572,7 +572,10 @@ dependencies = [
name = "niepce_rust"
version = "0.1.0"
dependencies = [
+ "cairo-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"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 251e8ce..f5d7ced 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,6 +10,9 @@ gettext-rs = "0.3.0"
glib = { version = "^0.9.0" }
gio-sys = "*"
gio = "^0.8.0"
+cairo-rs = "*"
+gdk = "*"
+gdk-pixbuf = "*"
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"
@@ -26,4 +29,4 @@ name = "niepce_rust"
crate-type = ["staticlib", "lib"]
[[example]]
-name = "widget-test"
\ No newline at end of file
+name = "widget-test"
diff --git a/build.rs b/build.rs
index 65cf8b0..5b08a40 100644
--- a/build.rs
+++ b/build.rs
@@ -19,6 +19,7 @@ fn main() {
.exclude_item("GtkWindow")
.exclude_item("GtkToolbar")
.exclude_item("GtkIconView")
+ .exclude_item("GtkCellRenderer")
.exclude_item("GtkWidget")
.exclude_item("GFileInfo")
.exclude_item("RgbColour")
diff --git a/crates/npc-engine/src/db/libfile.rs b/crates/npc-engine/src/db/libfile.rs
index 2776421..33fa62a 100644
--- a/crates/npc-engine/src/db/libfile.rs
+++ b/crates/npc-engine/src/db/libfile.rs
@@ -51,6 +51,18 @@ pub enum FileStatus {
Ok = 0,
/// File is missing
Missing = 1,
+ /// Invalid
+ Invalid = -1,
+}
+
+impl From<i32> for FileStatus {
+ fn from(t: i32) -> Self {
+ match t {
+ 0 => FileStatus::Ok,
+ 1 => FileStatus::Missing,
+ _ => FileStatus::Invalid,
+ }
+ }
}
impl From<i32> for FileType {
diff --git a/crates/npc-fwk/src/toolkit/clickable_cell_renderer.rs
b/crates/npc-fwk/src/toolkit/clickable_cell_renderer.rs
new file mode 100644
index 0000000..296ef87
--- /dev/null
+++ b/crates/npc-fwk/src/toolkit/clickable_cell_renderer.rs
@@ -0,0 +1,28 @@
+/*
+ * niepce - npc-fwk/toolkit/clickable_cell_renderer.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/>.
+ */
+
+/// Trait for get clicks from cell renderer.
+/// This is used to work around some bug in Gtk.
+pub trait ClickableCellRenderer {
+ fn hit(&mut self, x: i32, y: i32);
+ fn x(&self) -> i32;
+ fn y(&self) -> i32;
+ fn is_hit(&self) -> bool;
+ fn reset_hit(&mut self);
+}
diff --git a/crates/npc-fwk/src/toolkit/mod.rs b/crates/npc-fwk/src/toolkit/mod.rs
index 5adcdc8..659d60b 100644
--- a/crates/npc-fwk/src/toolkit/mod.rs
+++ b/crates/npc-fwk/src/toolkit/mod.rs
@@ -16,6 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
+pub mod clickable_cell_renderer;
pub mod mimetype;
pub mod widgets;
diff --git a/src/Makefile.am b/src/Makefile.am
index 7c04234..c0d780a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -56,6 +56,7 @@ RUST_SOURCES = \
@top_srcdir@/src/niepce/ui/dialogs/confirm.rs \
@top_srcdir@/src/niepce/ui/dialogs/requestnewfolder.rs \
@top_srcdir@/src/niepce/ui/thumb_nav.rs \
+ @top_srcdir@/src/niepce/ui/library_cell_renderer.rs \
$(NULL)
EXTRA_DIST = \
diff --git a/src/lib.rs b/src/lib.rs
index 2d38e64..dcaf462 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,6 +17,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+extern crate cairo;
+extern crate gdk;
+extern crate gdk_pixbuf;
extern crate gettextrs;
extern crate gio;
extern crate gio_sys;
diff --git a/src/libraryclient/uidataprovider.cpp b/src/libraryclient/uidataprovider.cpp
index c7d571b..f481bb0 100644
--- a/src/libraryclient/uidataprovider.cpp
+++ b/src/libraryclient/uidataprovider.cpp
@@ -58,15 +58,15 @@ void UIDataProvider::deleteLabel(int id)
}
}
-fwk::Option<fwk::RgbColourPtr> UIDataProvider::colourForLabel(int id) const
+fwk::Option<fwk::RgbColour> UIDataProvider::colourForLabel(int32_t id) const
{
for(auto label : m_labels) {
if (engine_db_label_id(label.get()) == id) {
- return fwk::Option<fwk::RgbColourPtr>(
- fwk::rgbcolour_clone(engine_db_label_colour(label.get())));
+ return fwk::Option<fwk::RgbColour>(
+ *engine_db_label_colour(label.get()));
}
}
- return fwk::Option<fwk::RgbColourPtr>();
+ return fwk::Option<fwk::RgbColour>();
}
diff --git a/src/libraryclient/uidataprovider.hpp b/src/libraryclient/uidataprovider.hpp
index f57981d..ce3c9a3 100644
--- a/src/libraryclient/uidataprovider.hpp
+++ b/src/libraryclient/uidataprovider.hpp
@@ -36,7 +36,7 @@ public:
void updateLabel(const eng::Label &);
void addLabel(const eng::Label & l);
void deleteLabel(int id);
- fwk::Option<fwk::RgbColourPtr> colourForLabel(int id) const;
+ fwk::Option<fwk::RgbColour> colourForLabel(int32_t id) const;
const eng::LabelList & getLabels() const
{ return m_labels; }
private:
diff --git a/src/niepce/ui/gridviewmodule.cpp b/src/niepce/ui/gridviewmodule.cpp
index 9ce98de..bc3a200 100644
--- a/src/niepce/ui/gridviewmodule.cpp
+++ b/src/niepce/ui/gridviewmodule.cpp
@@ -114,13 +114,17 @@ Gtk::Widget * GridViewModule::buildWidget()
libraryclient::UIDataProviderWeakPtr ui_data_provider(m_shell.get_ui_data_provider());
LibraryCellRenderer* libcell = Gtk::manage(
new LibraryCellRenderer(
- [ui_data_provider] (int label) {
+ [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) {
- return provider->colourForLabel(label);
+ auto c = provider->colourForLabel(label);
+ if (c.ok() && out) {
+ *out = c.unwrap();
+ return true;
+ }
}
- ERR_OUT("couldn't lock UI provider");
- return fwk::Option<fwk::RgbColourPtr>();
+ return false;
})
);
libcell->signal_rating_changed.connect(
diff --git a/src/niepce/ui/imageliststore.cpp b/src/niepce/ui/imageliststore.cpp
index b9ae872..f854f37 100644
--- a/src/niepce/ui/imageliststore.cpp
+++ b/src/niepce/ui/imageliststore.cpp
@@ -117,7 +117,7 @@ void ImageListStore::add_libfile(const eng::LibFilePtr & f)
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] = eng::FileStatus::Ok;
+ row[m_columns.m_file_status] = static_cast<gint>(eng::FileStatus::Ok);
m_idmap[engine_db_libfile_id(f.get())] = riter;
}
@@ -181,7 +181,7 @@ void ImageListStore::on_lib_notification(const eng::LibNotification &ln)
auto iter = m_idmap.find(id);
if (iter != m_idmap.end()) {
Gtk::TreeRow row = *(iter->second);
- row[m_columns.m_file_status] = status;
+ row[m_columns.m_file_status] = static_cast<gint>(status);
}
break;
}
diff --git a/src/niepce/ui/imageliststore.hpp b/src/niepce/ui/imageliststore.hpp
index a5bb3bd..a0ceebb 100644
--- a/src/niepce/ui/imageliststore.hpp
+++ b/src/niepce/ui/imageliststore.hpp
@@ -59,7 +59,7 @@ public:
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > m_pix;
Gtk::TreeModelColumn<eng::LibFilePtr> m_libfile;
Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> > m_strip_thumb;
- Gtk::TreeModelColumn<eng::FileStatus> m_file_status;
+ Gtk::TreeModelColumn<gint> m_file_status;
};
Gtk::TreePath get_path_from_id(eng::library_id_t id) const;
diff --git a/src/niepce/ui/library_cell_renderer.rs b/src/niepce/ui/library_cell_renderer.rs
new file mode 100644
index 0000000..b4d5f7d
--- /dev/null
+++ b/src/niepce/ui/library_cell_renderer.rs
@@ -0,0 +1,567 @@
+/*
+ * niepce - niepce/ui/library_cell_renderer.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 once_cell::unsync::Lazy;
+use std::cell::{Cell, RefCell};
+
+use cairo;
+use gdk;
+use gdk::prelude::*;
+use gdk_pixbuf::Pixbuf;
+use glib::subclass;
+use glib::subclass::prelude::*;
+use glib::translate::*;
+use glib::Type;
+use gtk;
+use gtk::prelude::*;
+use gtk::subclass::prelude::*;
+use gtk::CellRendererPixbufClass;
+
+use npc_engine::db::libfile::{FileStatus, FileType, LibFile};
+use npc_fwk::base::rgbcolour::RgbColour;
+use npc_fwk::toolkit::clickable_cell_renderer::ClickableCellRenderer;
+use npc_fwk::toolkit::widgets::rating_label::RatingLabel;
+
+const CELL_PADDING: i32 = 4;
+
+struct Emblems {
+ raw: Pixbuf,
+ raw_jpeg: Pixbuf,
+ img: Pixbuf,
+ video: Pixbuf,
+ unknown: Pixbuf,
+ status_missing: Pixbuf,
+ flag_reject: Pixbuf,
+ flag_pick: Pixbuf,
+}
+
+const EMBLEMS: Lazy<Emblems> = Lazy::new(|| Emblems {
+ raw: Pixbuf::new_from_resource("/org/gnome/Niepce/pixmaps/niepce-raw-fmt.png").unwrap(),
+ raw_jpeg: Pixbuf::new_from_resource("/org/gnome/Niepce/pixmaps/niepce-rawjpeg-fmt.png")
+ .unwrap(),
+ img: Pixbuf::new_from_resource("/org/gnome/Niepce/pixmaps/niepce-img-fmt.png").unwrap(),
+ video: Pixbuf::new_from_resource("/org/gnome/Niepce/pixmaps/niepce-video-fmt.png").unwrap(),
+ unknown: Pixbuf::new_from_resource("/org/gnome/Niepce/pixmaps/niepce-unknown-fmt.png").unwrap(),
+ status_missing: Pixbuf::new_from_resource("/org/gnome/Niepce/pixmaps/niepce-missing.png")
+ .unwrap(),
+ flag_reject: Pixbuf::new_from_resource("/org/gnome/Niepce/pixmaps/niepce-flag-reject.png")
+ .unwrap(),
+ flag_pick: Pixbuf::new_from_resource("/org/gnome/Niepce/pixmaps/niepce-flag-pick.png").unwrap(),
+});
+
+glib_wrapper! {
+ pub struct LibraryCellRenderer(
+ Object<subclass::simple::InstanceStruct<LibraryCellRendererPriv>,
+ subclass::simple::ClassStruct<LibraryCellRendererPriv>,
+ LibraryCellRendererClass>)
+ @extends gtk::CellRendererPixbuf, gtk::CellRenderer;
+
+ match fn {
+ get_type => || LibraryCellRendererPriv::get_type().to_glib(),
+ }
+}
+
+impl LibraryCellRenderer {
+ pub fn new(callback: Option<GetColourCallback>) -> Self {
+ let obj: Self = glib::Object::new(
+ Self::static_type(),
+ &[("mode", >k::CellRendererMode::Activatable)],
+ )
+ .expect("Failed to create Library Cell Renderer")
+ .downcast()
+ .expect("Created Library Cell Renderer is of wrong type");
+
+ let priv_ = LibraryCellRendererPriv::from_instance(&obj);
+ priv_.get_colour_callback.replace(callback);
+
+ obj
+ }
+}
+
+#[derive(Default)]
+struct ClickableCell {
+ x: i32,
+ y: i32,
+ hit: bool,
+}
+
+impl ClickableCellRenderer for LibraryCellRenderer {
+ fn hit(&mut self, x: i32, y: i32) {
+ let priv_ = LibraryCellRendererPriv::from_instance(self);
+ priv_
+ .clickable_cell
+ .replace(ClickableCell { x, y, hit: true });
+ }
+
+ fn x(&self) -> i32 {
+ let priv_ = LibraryCellRendererPriv::from_instance(self);
+ priv_.clickable_cell.borrow().x
+ }
+
+ fn y(&self) -> i32 {
+ let priv_ = LibraryCellRendererPriv::from_instance(self);
+ priv_.clickable_cell.borrow().y
+ }
+
+ fn is_hit(&self) -> bool {
+ let priv_ = LibraryCellRendererPriv::from_instance(self);
+ priv_.clickable_cell.borrow().hit
+ }
+
+ fn reset_hit(&mut self) {
+ let priv_ = LibraryCellRendererPriv::from_instance(self);
+ priv_.clickable_cell.borrow_mut().hit = false;
+ }
+}
+
+/// 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;
+
+pub struct LibraryCellRendererPriv {
+ libfile: RefCell<Option<CellLibFile>>,
+ status: Cell<FileStatus>,
+ size: Cell<i32>,
+ pad: Cell<i32>,
+ drawborder: Cell<bool>,
+ draw_emblem: Cell<bool>,
+ draw_rating: Cell<bool>,
+ draw_label: Cell<bool>,
+ draw_flag: Cell<bool>,
+ draw_status: Cell<bool>,
+ clickable_cell: RefCell<ClickableCell>,
+ get_colour_callback: RefCell<Option<GetColourCallback>>,
+}
+
+impl LibraryCellRendererPriv {
+ fn set_status(&self, status: FileStatus) {
+ self.status.set(status);
+ }
+
+ fn set_libfile(&self, libfile: Option<CellLibFile>) {
+ self.libfile.replace(libfile);
+ }
+
+ fn do_draw_thumbnail(&self, cr: &cairo::Context, pixbuf: &Pixbuf, r: &gdk::Rectangle) {
+ let w = pixbuf.get_width();
+ let h = pixbuf.get_height();
+ let offset_x = (self.size.get() - w) / 2;
+ let offset_y = (self.size.get() - h) / 2;
+ let x: f64 = (r.x + self.pad.get() + offset_x).into();
+ let y: f64 = (r.y + self.pad.get() + offset_y).into();
+
+ cr.set_source_rgb(1.0, 1.0, 1.0);
+ cr.rectangle(x, y, w.into(), h.into());
+ cr.stroke();
+
+ cr.set_source_pixbuf(&pixbuf, x, y);
+ cr.paint();
+ }
+
+ fn do_draw_flag(cr: &cairo::Context, flag: i32, r: &gdk::Rectangle) {
+ if flag == 0 {
+ return;
+ }
+ let pixbuf = match flag {
+ -1 => EMBLEMS.flag_reject.clone(),
+ 1 => EMBLEMS.flag_pick.clone(),
+ _ => return,
+ };
+
+ let w = pixbuf.get_width();
+ let x: f64 = (r.x + r.width - CELL_PADDING - w).into();
+ let y: f64 = (r.y + CELL_PADDING).into();
+ cr.set_source_pixbuf(&pixbuf, x, y);
+ cr.paint();
+ }
+
+ fn do_draw_status(cr: &cairo::Context, status: FileStatus, r: &gdk::Rectangle) {
+ if status == FileStatus::Ok {
+ return;
+ }
+ let x: f64 = (r.x + CELL_PADDING).into();
+ let y: f64 = (r.y + CELL_PADDING).into();
+ cr.set_source_pixbuf(&EMBLEMS.status_missing, x, y);
+ cr.paint();
+ }
+
+ fn do_draw_format_emblem(cr: &cairo::Context, emblem: &Pixbuf, r: &gdk::Rectangle) -> i32 {
+ let w = emblem.get_width();
+ let h = emblem.get_height();
+ let left = CELL_PADDING + w;
+ let x: f64 = (r.x + r.width - left).into();
+ let y: f64 = (r.y + r.height - CELL_PADDING - h).into();
+ cr.set_source_pixbuf(emblem, x, y);
+ cr.paint();
+ left
+ }
+
+ fn do_draw_label(cr: &cairo::Context, right: i32, colour: RgbColour, r: &gdk::Rectangle) {
+ const LABEL_SIZE: i32 = 15;
+ let x: f64 = (r.x + r.width - CELL_PADDING - right - CELL_PADDING - LABEL_SIZE).into();
+ let y: f64 = (r.y + r.height - CELL_PADDING - LABEL_SIZE).into();
+
+ cr.rectangle(x, y, LABEL_SIZE.into(), LABEL_SIZE.into());
+ cr.set_source_rgb(1.0, 1.0, 1.0);
+ cr.stroke();
+ cr.rectangle(x, y, LABEL_SIZE.into(), LABEL_SIZE.into());
+ let rgb: gdk::RGBA = colour.into();
+ cr.set_source_rgba(rgb.red, rgb.green, rgb.blue, rgb.alpha);
+ cr.fill();
+ }
+
+ fn get_colour(&self, label_id: i32) -> Option<RgbColour> {
+ if let Some(f) = *self.get_colour_callback.borrow() {
+ unsafe {
+ let mut c = RgbColour::default();
+ if f(label_id, &mut c) {
+ return Some(c);
+ }
+ }
+ }
+ None
+ }
+}
+
+static PROPERTIES: [subclass::Property; 2] = [
+ subclass::Property("libfile", |libfile| {
+ glib::ParamSpec::boxed(
+ libfile,
+ "Library File",
+ "File from the library in the cell",
+ CellLibFile::get_type(),
+ glib::ParamFlags::READWRITE,
+ )
+ }),
+ subclass::Property("status", |status| {
+ glib::ParamSpec::int(
+ status,
+ "File Status",
+ "Status of the file in the cell",
+ FileStatus::Ok as i32,
+ FileStatus::Missing as i32,
+ FileStatus::Ok as i32,
+ glib::ParamFlags::READWRITE,
+ )
+ }),
+];
+
+impl ObjectSubclass for LibraryCellRendererPriv {
+ const NAME: &'static str = "LibraryCellRenderer";
+ type ParentType = gtk::CellRendererPixbuf;
+ type Instance = subclass::simple::InstanceStruct<Self>;
+ type Class = subclass::simple::ClassStruct<Self>;
+
+ glib_object_subclass!();
+
+ fn class_init(klass: &mut Self::Class) {
+ klass.install_properties(&PROPERTIES);
+ klass.add_signal(
+ "rating-changed",
+ glib::SignalFlags::RUN_LAST,
+ &[Type::U64, Type::I32],
+ Type::Unit,
+ );
+ }
+
+ fn new() -> Self {
+ Self {
+ libfile: RefCell::new(None),
+ status: Cell::new(FileStatus::Ok),
+ size: Cell::new(160),
+ pad: Cell::new(16),
+ drawborder: Cell::new(true),
+ draw_emblem: Cell::new(true),
+ draw_rating: Cell::new(true),
+ draw_label: Cell::new(true),
+ draw_flag: Cell::new(true),
+ draw_status: Cell::new(true),
+ clickable_cell: RefCell::new(ClickableCell::default()),
+ get_colour_callback: RefCell::new(None),
+ }
+ }
+}
+
+impl ObjectImpl for LibraryCellRendererPriv {
+ glib_object_impl!();
+
+ fn constructed(&self, obj: &glib::Object) {
+ self.parent_constructed(obj);
+ }
+
+ fn set_property(&self, _obj: &glib::Object, id: usize, value: &glib::Value) {
+ let prop = &PROPERTIES[id];
+ match *prop {
+ subclass::Property("libfile", ..) => {
+ let libfile = value
+ .get::<&CellLibFile>()
+ .expect("type conformity checked by `Object::set_property`")
+ .map(|f| f.clone());
+ self.set_libfile(libfile);
+ }
+ subclass::Property("status", ..) => {
+ let status: i32 = value
+ .get_some()
+ .expect("type conformity checked by `Object::set_property`");
+ self.set_status(FileStatus::from(status));
+ }
+ _ => unimplemented!(),
+ }
+ }
+
+ fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
+ let prop = &PROPERTIES[id];
+
+ match *prop {
+ subclass::Property("libfile", ..) => Ok(self.libfile.borrow().to_value()),
+ subclass::Property("status", ..) => Ok((self.status.get() as i32).to_value()),
+ _ => unimplemented!(),
+ }
+ }
+}
+
+impl CellRendererPixbufImpl for LibraryCellRendererPriv {}
+
+impl CellRendererImpl for LibraryCellRendererPriv {
+ fn get_preferred_width<P: IsA<gtk::Widget>>(
+ &self,
+ _renderer: >k::CellRenderer,
+ _widget: &P,
+ ) -> (i32, i32) {
+ let maxdim: i32 = self.size.get() + self.pad.get() * 2;
+ (maxdim, maxdim)
+ }
+
+ fn get_preferred_height<P: IsA<gtk::Widget>>(
+ &self,
+ _renderer: >k::CellRenderer,
+ _widget: &P,
+ ) -> (i32, i32) {
+ let maxdim: i32 = self.size.get() + self.pad.get() * 2;
+ (maxdim, maxdim)
+ }
+
+ fn render<P: IsA<gtk::Widget>>(
+ &self,
+ _renderer: >k::CellRenderer,
+ cr: &cairo::Context,
+ widget: &P,
+ _background_area: &gdk::Rectangle,
+ cell_area: &gdk::Rectangle,
+ flags: gtk::CellRendererState,
+ ) {
+ let self_ = self.get_instance();
+ let xpad = self_.get_property_xpad();
+ let ypad = self_.get_property_ypad();
+
+ let mut r = cell_area.clone();
+ r.x += xpad as i32;
+ r.y += ypad as i32;
+
+ let file = self.libfile.borrow();
+
+ let style_context = widget.get_style_context();
+
+ style_context.save();
+ style_context.set_state(if flags.contains(gtk::CellRendererState::SELECTED) {
+ gtk::StateFlags::SELECTED
+ } else {
+ gtk::StateFlags::NORMAL
+ });
+ gtk::render_background(
+ &style_context,
+ cr,
+ (r.x).into(),
+ (r.y).into(),
+ (r.width).into(),
+ (r.height).into(),
+ );
+
+ if self.drawborder.get() {
+ gtk::render_frame(
+ &style_context,
+ cr,
+ (r.x).into(),
+ (r.y).into(),
+ (r.width).into(),
+ (r.height).into(),
+ );
+ }
+ style_context.restore();
+
+ if let Some(pixbuf) = self_.get_property_pixbuf() {
+ self.do_draw_thumbnail(cr, &pixbuf, &r);
+ }
+ if self.draw_rating.get() {
+ let rating = match &*file {
+ Some(f) => f.0.rating(),
+ None => 0,
+ };
+ let x: f64 = (r.x + CELL_PADDING).into();
+ let y: f64 = (r.y + r.height - CELL_PADDING).into();
+ RatingLabel::draw_rating(
+ cr,
+ rating,
+ &RatingLabel::get_star(),
+ &RatingLabel::get_unstar(),
+ x,
+ y,
+ );
+ }
+ if self.draw_flag.get() {
+ match &*file {
+ Some(f) => Self::do_draw_flag(cr, f.0.flag(), &r),
+ None => {}
+ }
+ }
+
+ let status = self.status.get();
+ if self.draw_status.get() && status != FileStatus::Ok {
+ Self::do_draw_status(cr, status, &r);
+ }
+
+ if self.draw_emblem.get() {
+ let file_type = match &*file {
+ Some(f) => f.0.file_type(),
+ None => FileType::UNKNOWN,
+ };
+ let emblem: Pixbuf = match file_type {
+ FileType::RAW => EMBLEMS.raw.clone(),
+ FileType::RAW_JPEG => EMBLEMS.raw_jpeg.clone(),
+ FileType::IMAGE => EMBLEMS.img.clone(),
+ FileType::VIDEO => EMBLEMS.video.clone(),
+ FileType::UNKNOWN => EMBLEMS.unknown.clone(),
+ };
+ let left = Self::do_draw_format_emblem(cr, &emblem, &r);
+
+ if self.draw_label.get() {
+ let label_id = match &*file {
+ Some(f) => f.0.label(),
+ None => 0,
+ };
+ if label_id != 0 {
+ if let Some(colour) = self.get_colour(label_id) {
+ Self::do_draw_label(cr, left, colour, &r);
+ }
+ }
+ }
+ }
+ }
+
+ fn activate<P: IsA<gtk::Widget>>(
+ &self,
+ _renderer: >k::CellRenderer,
+ _event: Option<&gdk::Event>,
+ _widget: &P,
+ _path: &str,
+ _background_area: &gdk::Rectangle,
+ cell_area: &gdk::Rectangle,
+ _flags: gtk::CellRendererState,
+ ) -> bool {
+ let mut instance = self
+ .get_instance()
+ .downcast::<LibraryCellRenderer>()
+ .unwrap();
+
+ if instance.is_hit() {
+ instance.reset_hit();
+
+ // hit test with the rating region
+ let xpad = instance.get_property_xpad();
+ let ypad = instance.get_property_ypad();
+ let mut r = cell_area.clone();
+ r.x += xpad as i32;
+ r.y += ypad as i32;
+
+ let (rw, rh) = RatingLabel::get_geometry();
+ let rect = gdk::Rectangle {
+ x: r.x + CELL_PADDING,
+ y: r.y + r.height - rh - CELL_PADDING,
+ width: rw,
+ height: rh,
+ };
+ let x = instance.x();
+ let y = instance.y();
+ dbg_out!(
+ "r({}, {}, {}, {}) p({}, {})",
+ rect.x,
+ rect.y,
+ rect.width,
+ rect.height,
+ x,
+ y
+ );
+ let hit = (rect.x <= x)
+ && (rect.x + rect.width >= x)
+ && (rect.y <= y)
+ && (rect.y + rect.height >= y);
+ if !hit {
+ dbg_out!("not a hit");
+ return false;
+ }
+
+ // hit test for the rating value
+ let new_rating = RatingLabel::rating_value_from_hit_x((x - rect.x).into());
+ dbg_out!("new_rating {}", new_rating);
+
+ let file = self.libfile.borrow();
+ if let Some(f) = &*file {
+ if f.0.rating() != new_rating {
+ // emit signal if changed
+ if let Err(err) = instance.emit("rating-changed", &[&f.0.id(), &new_rating]) {
+ err_out!("Can't emit rating-changed signal: {}", err);
+ }
+ }
+ }
+ true
+ } else {
+ false
+ }
+ }
+}
+
+// allow subclassing this
+pub trait LibraryCellRendererImpl: CellRendererPixbufImpl + 'static {}
+
+unsafe impl<T: ObjectSubclass + LibraryCellRendererImpl> IsSubclassable<T>
+ for LibraryCellRendererClass
+{
+ fn override_vfuncs(&mut self) {
+ <CellRendererPixbufClass as IsSubclassable<T>>::override_vfuncs(self);
+ }
+}
+
+// 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>,
+) -> *mut gtk_sys::GtkCellRenderer {
+ LibraryCellRenderer::new(get_colour)
+ .upcast::<gtk::CellRenderer>()
+ .to_glib_full()
+}
diff --git a/src/niepce/ui/librarycellrenderer.cpp b/src/niepce/ui/librarycellrenderer.cpp
index 7c4aec3..105adc9 100644
--- a/src/niepce/ui/librarycellrenderer.cpp
+++ b/src/niepce/ui/librarycellrenderer.cpp
@@ -255,7 +255,7 @@ LibraryCellRenderer::render_vfunc(const Cairo::RefPtr<Cairo::Context>& cr,
draw_flag(cr, engine_db_libfile_flag(file.get()), r);
}
- auto status = m_statusproperty.get_value();
+ auto status = static_cast<eng::FileStatus>(m_statusproperty.get_value());
if (m_drawstatus && status != eng::FileStatus::Ok) {
draw_status(cr, status, r);
}
@@ -285,10 +285,11 @@ LibraryCellRenderer::render_vfunc(const Cairo::RefPtr<Cairo::Context>& cr,
if (m_drawlabel) {
uint32_t label_id = engine_db_libfile_label(file.get());
if (label_id != 0) {
- auto result = m_get_colour(label_id);
- DBG_ASSERT(!result.empty(), "colour not found");
- if (!result.empty()) {
- drawLabel(cr, left, *result.unwrap(), r);
+ ffi::RgbColour colour;
+ if (m_get_colour(label_id, &colour)) {
+ drawLabel(cr, left, colour, r);
+ } else {
+ DBG_ASSERT(false, "colour not found");
}
}
}
diff --git a/src/niepce/ui/librarycellrenderer.hpp b/src/niepce/ui/librarycellrenderer.hpp
index 8e83d05..091f6dd 100644
--- a/src/niepce/ui/librarycellrenderer.hpp
+++ b/src/niepce/ui/librarycellrenderer.hpp
@@ -34,7 +34,7 @@ class LibraryCellRenderer
, public fwk::ClickableCellRenderer
{
public:
- typedef std::function<fwk::Option<fwk::RgbColourPtr>(int)> GetColourFunc;
+ typedef std::function<bool (int32_t, fwk::RgbColour*)> GetColourFunc;
LibraryCellRenderer(const GetColourFunc& get_colour);
virtual void get_preferred_width_vfunc(Gtk::Widget& widget, int& minimum_width, int& natural_width)
const override;
@@ -93,7 +93,7 @@ private:
bool m_drawflag;
bool m_drawstatus;
Glib::Property<eng::LibFilePtr> m_libfileproperty;
- Glib::Property<eng::FileStatus> m_statusproperty;
+ Glib::Property<gint> m_statusproperty;
Glib::RefPtr<Gdk::Pixbuf> m_raw_format_emblem;
Glib::RefPtr<Gdk::Pixbuf> m_rawjpeg_format_emblem;
diff --git a/src/niepce/ui/mod.rs b/src/niepce/ui/mod.rs
index 0d3e07e..ec86fe3 100644
--- a/src/niepce/ui/mod.rs
+++ b/src/niepce/ui/mod.rs
@@ -19,4 +19,5 @@
pub mod dialogs;
pub mod imagetoolbar;
+pub mod library_cell_renderer;
pub mod thumb_nav;
diff --git a/src/niepce/ui/thumbstripview.cpp b/src/niepce/ui/thumbstripview.cpp
index 35bea95..3129d87 100644
--- a/src/niepce/ui/thumbstripview.cpp
+++ b/src/niepce/ui/thumbstripview.cpp
@@ -85,13 +85,17 @@ ThumbStripView::ThumbStripView(const Glib::RefPtr<ui::ImageListStore> & store,
{
m_renderer = manage(
new ThumbStripCell(
- [ui_data_provider] (int label) {
+ [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) {
- return provider->colourForLabel(label);
+ auto c = provider->colourForLabel(label);
+ if (c.ok() && out) {
+ *out = c.unwrap();
+ return true;
+ }
}
- ERR_OUT("couldn't lock UI provider");
- return fwk::Option<fwk::RgbColourPtr>();
+ return false;
})
);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]