I am trying to draw an image on a very basic GUI. I am using GTK for the GUI and want to use the plotters crate for the drawing but am having issues initiating the Backend that plotters uses.
I have successfully managed to use the BitMapBackend to draw to a file - there is no shortage of examples on the internet for this. However, I cannot for the life of me find an example of how to use the CairoBackend to draw onto a gtk DrawingArea.
My issue arises when I try to connect the draw event to the GTK DrawingArea. I use the connect_draw method which works as expected returning a context to pass to the CairoBackEnd. The problem is that the type of context returned by connect_draw is not compatible with the type of context required by the CairoBackend. I receive context of type 'gtk::cairo::Context' (defined in cairo-rs v0.16.7) but the backend requires a context of 'cairo::context:Context' (defined in cairo-rs v0.15.12). Clearly my dependencies are using different versions of the cairo-rs crate. Presumably, the versions of my dependencies are not compatible with each other. How can I fix this? How do I find out what version of each dependency will work with the others? My cargo.toml file contains:
[package]
name = "testing3"
version = "0.1.0"
edition = "2021"
[dependencies]
gtk = "0.16.2"
plotters = "0.3.4"
plotters-cairo = "0.3.2"
My rust code is:
use gtk::prelude::*;
use plotters::prelude::*;
use gtk::{Application, ApplicationWindow};
fn main() {
let app = Application::builder().build();
app.connect_activate(build_gui);
app.run();
}
fn build_gui(app: &Application){
let win = ApplicationWindow::builder().application(app).default_width(320).default_height(200).title("Test").build();
let da: gtk::DrawingArea = gtk::DrawingArea::builder().build();
da.connect_draw(move|_, c|{
let root = plotters_cairo::CairoBackend::new(c, (1024, 768)).unwrap().into_drawing_area();
gtk::Inhibit(false)
});
win.add(&da);
win.show_all();
}
my error message is:
--> src/main.rs:21:49
|
21 | let root = plotters_cairo::CairoBackend::new(c, (1024, 768)).unwrap().into_drawing_area();
| --------------------------------- ^ expected struct `cairo::context::Context`, found struct `gtk::cairo::Context`
| |
| arguments to this function are incorrect
|
= note: struct `gtk::cairo::Context` and struct `cairo::context::Context` have similar names, but are actually distinct types
note: struct `gtk::cairo::Context` is defined in crate `cairo`
--> /home/maindesktop/.cargo/registry/src/github.com-1ecc6299db9ec823/cairo-rs-0.16.7/src/context.rs:72:1
|
72 | pub struct Context(ptr::NonNull<cairo_t>);
| ^^^^^^^^^^^^^^^^^^
note: struct `cairo::context::Context` is defined in crate `cairo`
--> /home/maindesktop/.cargo/registry/src/github.com-1ecc6299db9ec823/cairo-rs-0.15.12/src/context.rs:72:1
|
72 | pub struct Context(ptr::NonNull<cairo_t>);
| ^^^^^^^^^^^^^^^^^^
= note: perhaps two different versions of crate `cairo` are being used?
note: associated function defined here
--> /home/maindesktop/.cargo/registry/src/github.com-1ecc6299db9ec823/plotters-cairo-0.3.2/src/backend.rs:70:12
|
70 | pub fn new(context: &'a CairoContext, (w, h): (u32, u32)) -> Result<Self, CairoError> {
| ^^^
For more information about this error, try `rustc --explain E0308`.
error: could not compile `testing3` due to previous error
------------------
(program exited with code: 101)
So with more digging around I have found the solution.
As I identified from the error message, my code had a compatibility problem. The gtk v0.16.2 dependency in my toml file depended itself on cairo-rs v0.16.7 where as the plotters-cairo v0.3.2 depended on cairo-rs v15.12. Clearly, I had to use an earlier version of the gtk dependency - one that depended on cairo-rs v15.12. But which one.
On the Doc.rs website I could find the gtk crate documents on https://docs.rs/gtk/0.6.0/gtk/. A tab on top left, gtk-0.6.0, on being selected provided both dependency data and versioning options. I could see that the latest version of the gtk crate did indeed depend on cairo-rs 0.6.0. Selecting the various versions I was able to find the latest version that still depended on cairo-rs v15.xx. In this case it was gtk v0.15.5. Once I replaced my gtk dependency with that version, all was good. So my new toml was:
[package]
name = "testing3"
version = "0.1.0"
edition = "2021"
[dependencies]
gtk = "0.15.5"
plotters = "0.3.4"
plotters-cairo = "0.3.2"
Now by adding the code:
c.rectangle(10.0, 10.0, 70.0, 70.0);
c.fill().expect("Drawing failed");
root.fill(&RED).unwrap();
above my gtk::Inhibit(false) statement, I could indeed create a red rectangle