I'm trying to modify a pixbuf when the left mouse button is clicked but I don't think it's being modified. The modify_pixel function simply takes a specific pixel from the pixbuf and modifies it.
fn build_ui(application: &Application) {
let pixbuf = Pixbuf::from_file("assets/map.png").expect("msg");
let pixbuf = Rc::new(RefCell::new(pixbuf));
let gesture = GestureClick::new();
let pixbuf_clone = Rc::clone(&pixbuf);
gesture.connect_pressed(move |_gesture, _n_press, x, y| {
let mut pixbuf = pixbuf_clone.borrow_mut();
let position = [x as usize, y as usize];
if position[0] < pixbuf.width() as usize && position[1] < pixbuf.height() as usize {
modify_pixel(&mut pixbuf, position);
} else {
println!("Out of bounds");
}
});
let picture = Picture::for_pixbuf(Some(&pixbuf.borrow()).expect("No se pudo crear el Picture"));
let window = ApplicationWindow::builder()
.application(application)
.default_height(800)
.default_width(800)
.title("My GTK App")
.build();
window.set_child(Some(&picture));
window.add_controller(gesture);
window.present();
}
fn modify_pixel(pixbuf: &mut Pixbuf, position: [usize;2]){
let pixels = unsafe {pixbuf.pixels()};
let rowstride = pixbuf.rowstride() as usize;
let n_channels = pixbuf.n_channels() as usize;
let offset = position[1] * rowstride + position[0] * n_channels;
let mut pixels = pixels.to_vec();
pixels[offset] = 255;
pixels[offset + 1] = 0;
pixels[offset + 2] = 0;
*pixbuf = Pixbuf::from_mut_slice(
pixels,
Colorspace::Rgb,
pixbuf.has_alpha(),
8,
pixbuf.width(),
pixbuf.height(),
rowstride as i32,
);
}
I'm also not sure if using a Gesture is the most appropriate option. I tried to modify the picture inside the clause but I had the same problem
You need to use set_pixbuf
in order to update the Pixbuf
like so:
fn build_ui(application: &Application) {
let pixbuf = Pixbuf::from_file("assets/map.png").expect("msg");
let pixbuf = Rc::new(RefCell::new(pixbuf));
let pixbuf_clone = Rc::clone(&pixbuf);
let gesture = GestureClick::new();
let picture = Picture::for_pixbuf(Some(&pixbuf.borrow()).expect("Failed to load image."));
let window = ApplicationWindow::builder()
.application(application)
.default_height(800)
.default_width(800)
.title("GTK Pixbuf test")
.build();
window.set_child(Some(&picture));
gesture.connect_pressed(move |_gesture, _n_press, x, y| {
let mut pixbuf = pixbuf_clone.borrow_mut();
let position = [x as usize, y as usize];
if position[0] < pixbuf.width() as usize && position[1] < pixbuf.height() as usize {
modify_pixel(&mut pixbuf, position);
picture.set_pixbuf(Some(&pixbuf));
} else {
println!("Out of bounds");
}
});
window.add_controller(gesture);
window.present();
}
This will change the pixel to red when clicking on the image with the mouse.
I suppose this is not exactly what you would like to do though, for which reason, I would suggest looking into the DrawingArea example.
Pixbuf related methods are deprecated since GTK v4.12 btw. and should be replaced by paintable
as can be seen below:
fn build_ui(application: &Application) {
let pixbuf = Pixbuf::from_file("assets/blank.png").expect("msg");
let pixbuf = Rc::new(RefCell::new(pixbuf));
let pixbuf_clone = Rc::clone(&pixbuf);
let gesture = GestureClick::new();
let picture = Picture::for_paintable(&Texture::for_pixbuf(&pixbuf.borrow()));
let window = ApplicationWindow::builder()
.application(application)
.default_height(800)
.default_width(800)
.title("GTK Pixbuf test")
.build();
window.set_child(Some(&picture));
gesture.connect_pressed(move |_gesture, _n_press, x, y| {
let mut pixbuf = pixbuf_clone.borrow_mut();
let position = [x as usize, y as usize];
if position[0] < pixbuf.width() as usize && position[1] < pixbuf.height() as usize {
modify_pixel(&mut pixbuf, position);
picture.set_paintable(Some(&Texture::for_pixbuf(&pixbuf)));
} else {
println!("Out of bounds");
}
});
window.add_controller(gesture);
window.present();
}