Skip to content

Commit

Permalink
Add a context menu in the main history view
Browse files Browse the repository at this point in the history
Currently it allows one to copy the path to the screenshot or the
screenshot itself, but it can be expanded.

Related: Better history widgets #17
  • Loading branch information
RealKC committed Jul 23, 2023
1 parent 9c04248 commit 57786c2
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 15 deletions.
5 changes: 1 addition & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,5 @@
"editor.formatOnSave": false
},
"rust-analyzer.check.command": "cranky",
"rust-analyzer.checkOnSave": false,
"rust-analyzer.check.extraArgs": [
"--target target/r-a"
]
"rust-analyzer.checkOnSave": true,
}
49 changes: 43 additions & 6 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::env;
use core::panic;
use std::{env, process::Command};

fn main() {
// See: https://docs.rs/diesel_migrations/2.0.0-rc.1/diesel_migrations/macro.embed_migrations.html#automatic-rebuilds
Expand All @@ -8,15 +9,51 @@ fn main() {
println!("cargo:rustc-cfg=kcshot_linting");
}

glib_build_tools::compile_resources(
&["resources"],
"resources/resources.gresource.xml",
"compiled.gresource",
);
let mut blueprintc = "blueprint-compiler".to_owned();

// A hack to make the build work when building using meson and blueprint-compiler isn't in the path
if let Ok(blueprint_path) = env::var("BLUEPRINT_PATH") {
let path = env::var("PATH").unwrap();
println!("cargo:rustc-env=PATH={path}:{blueprint_path}");
blueprintc = format!("{blueprint_path}/{blueprintc}");
}

let blueprint_dir = env::var("OUT_DIR").unwrap() + "/resources";
compile_blueprints(
&blueprintc,
&["src/history/context_menu.blp"],
&blueprint_dir,
);

glib_build_tools::compile_resources(
&["resources", &blueprint_dir],
"resources/resources.gresource.xml",
"compiled.gresource",
);
}

fn compile_blueprints(blueprintc: &str, blueprints: &[&str], target: &str) {
let mut blueprintc = Command::new(blueprintc);
// blueprintc.args(["batch-compile", target, "src/"]);
blueprintc.arg("batch-compile");
blueprintc.arg(target);
blueprintc.arg("src/");

for blueprint in blueprints {
println!("cargo:rerun-if-changed={blueprint}");
blueprintc.arg(blueprint);
}

let output = blueprintc
.output()
.expect("Failed to execute blueprint-compiler");

if !output.status.success() {
panic!(
"blueprint-compiler returned {}, with stdout=:\n{}\n\t and stderr:\n{}",
output.status,
std::str::from_utf8(&output.stdout).unwrap(),
std::str::from_utf8(&output.stderr).unwrap()
);
}
}
1 change: 1 addition & 0 deletions resources/resources.gresource.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@
<file>editor/tool-colourpicker.png</file>

<!-- UI files generated from blueprints in build.rs -->
<file preprocess="xml-stripblanks" alias="ui/history/context_menu.ui">history/context_menu.ui</file>
</gresource>
</gresources>
32 changes: 28 additions & 4 deletions src/appwindow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod underlying {
use std::{cell::RefCell, process::Command};

use gtk4::{
gdk,
glib::{self, clone, ParamSpec, Properties},
prelude::*,
subclass::{application_window::ApplicationWindowImpl, prelude::*},
Expand All @@ -30,7 +31,7 @@ mod underlying {
use once_cell::unsync::OnceCell;

use crate::{
editor::EditorWindow, historymodel::RowData, kcshot::KCShot,
editor::EditorWindow, history, historymodel::RowData, kcshot::KCShot,
settings_window::SettingsWindow,
};

Expand Down Expand Up @@ -91,7 +92,7 @@ mod underlying {
let selection_model = gtk4::SingleSelection::new(Some(list_model));
self.image_grid.set_model(Some(&selection_model));

let factory = build_item_factory();
let factory = build_item_factory(selection_model);

self.image_grid.set_factory(Some(&factory));

Expand Down Expand Up @@ -170,7 +171,7 @@ mod underlying {
}
}

fn build_item_factory() -> gtk4::SignalListItemFactory {
fn build_item_factory(model: gtk4::SingleSelection) -> gtk4::SignalListItemFactory {
let factory = gtk4::SignalListItemFactory::new();

factory.connect_setup(|_this, list_item| {
Expand All @@ -182,7 +183,7 @@ mod underlying {
list_item.set_child(Some(&picture));
});

factory.connect_bind(|_this, list_item| {
factory.connect_bind(move |_this, list_item| {
let object = list_item
.item()
.and_downcast::<RowData>()
Expand All @@ -193,6 +194,29 @@ mod underlying {
.and_downcast::<gtk4::Picture>()
.expect("The child has to exist and it should be a gtk4::Picture");

let mouse = gtk4::GestureClick::builder()
.button(gdk::BUTTON_SECONDARY)
.build();
mouse.connect_released(
clone!(@strong list_item, @strong model, @strong picture, @strong object => move |_, _, x, y| {
model.set_selected(list_item.position());

match object.context_menu() {
Some(context_menu) => {
context_menu.set_pointing_to(Some(&gdk::Rectangle::new(x as i32, y as i32, 1, 1)));
context_menu.popup();
}
None => {
let context_menu = history::context_menu(object.clone(), picture.upcast_ref());
context_menu.set_pointing_to(Some(&gdk::Rectangle::new(x as i32, y as i32, 1, 1)));
context_menu.popup();
object.set_context_menu(context_menu);
}
}
}),
);
picture.add_controller(mouse);

if let Some(path) = object.path() {
picture.set_filename(Some(&path));
}
Expand Down
3 changes: 3 additions & 0 deletions src/history.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod context_menu;

pub use context_menu::context_menu;
6 changes: 6 additions & 0 deletions src/history/context_menu.blp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using Gtk 4.0;

menu history_context_menu {
item (_("Copy image"), "ctx_menu.copy_image")
item (_("Copy path"), "ctx_menu.copy_path")
}
56 changes: 56 additions & 0 deletions src/history/context_menu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use gtk4::{gdk, gio, prelude::*};

use crate::historymodel::RowData;

/// Creates a context menu with the usual operations you'd expect from a context menu on a history entry
pub fn context_menu(data: RowData, parent: &gtk4::Widget) -> gtk4::PopoverMenu {
let builder = gtk4::Builder::from_resource("/kc/kcshot/ui/history/context_menu.ui");
let model = builder
.object::<gio::MenuModel>("history_context_menu")
.unwrap();

let menu = gtk4::PopoverMenu::builder()
.menu_model(&model)
.autohide(true)
.has_arrow(false)
.halign(gtk4::Align::Start)
.build();
menu.set_parent(parent);

let actions = gio::SimpleActionGroup::new();
menu.insert_action_group("ctx_menu", Some(&actions));

let copy_path = gio::SimpleAction::new("copy_path", None);
let path = data.path();
copy_path.connect_activate({
let menu = menu.clone();
move |_, _| {
menu.popdown();
if let Some(path) = &path {
clipboard().set_text(path);
}
}
});
actions.add_action(&copy_path);

let copy_image = gio::SimpleAction::new("copy_image", None);
let path = data.path();
copy_image.connect_activate({
let menu = menu.clone();
move |_, _| {
menu.popdown();
if let Some(path) = &path {
clipboard()
.set_texture(&gdk::Texture::from_file(&gio::File::for_path(path)).unwrap());
}
}
});
actions.add_action(&copy_image);

menu
}

#[track_caller]
fn clipboard() -> gdk::Clipboard {
gdk::Display::default().unwrap().clipboard()
}
14 changes: 13 additions & 1 deletion src/historymodel/rowdata.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use gtk4::glib;
use gtk4::{glib, subclass::prelude::*};

use crate::db::models::Screenshot;

Expand All @@ -21,6 +21,14 @@ impl RowData {
.property("url", url)
.build()
}

pub fn set_context_menu(&self, menu: gtk4::PopoverMenu) {
self.imp().context_menu.replace(Some(menu));
}

pub fn context_menu(&self) -> Option<gtk4::PopoverMenu> {
self.imp().context_menu.borrow().clone()
}
}

mod underlying {
Expand All @@ -37,6 +45,10 @@ mod underlying {
pub(super) time: RefCell<String>,
#[property(get, set, default_value = None)]
pub(super) url: RefCell<Option<String>>,

/// We need to keep the context menu here because creating context menus on every right click
/// behaves strangely
pub(super) context_menu: RefCell<Option<gtk4::PopoverMenu>>,
}

#[glib::object_subclass]
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use self::kcshot::KCShot;
mod appwindow;
mod db;
mod editor;
mod history;
mod historymodel;
mod kcshot;
mod postcapture;
Expand Down

0 comments on commit 57786c2

Please sign in to comment.