init context menu for page tabs

This commit is contained in:
yggverse 2024-11-04 04:52:33 +02:00
parent 51f543143d
commit b443d1c58e
6 changed files with 93 additions and 27 deletions

View File

@ -52,7 +52,7 @@ impl App {
let action_page_home = Action::new("win", false, None); let action_page_home = Action::new("win", false, None);
let action_page_history_back = Action::new("win", false, None); let action_page_history_back = Action::new("win", false, None);
let action_page_history_forward = Action::new("win", false, None); let action_page_history_forward = Action::new("win", false, None);
let action_page_reload = Action::new("win", true, None); let action_page_reload = Action::new_stateful("win", true, None, &0.to_variant()); // @TODO
let action_page_pin = Action::new("win", true, None); let action_page_pin = Action::new("win", true, None);
// Init GTK // Init GTK

View File

@ -4,7 +4,7 @@
use gtk::{ use gtk::{
gio::SimpleAction, gio::SimpleAction,
glib::{gformat, uuid_string_random, GString, VariantTy}, glib::{gformat, uuid_string_random, GString, Variant, VariantTy},
prelude::ActionExt, prelude::ActionExt,
}; };
@ -27,6 +27,23 @@ impl Action {
Self { group, simple } Self { group, simple }
} }
pub fn new_stateful(
group: &str,
is_enabled: bool,
parameter_type: Option<&VariantTy>,
state: &Variant,
) -> Self {
// Create random action name as no static values should be in use
let simple = SimpleAction::new_stateful(&uuid_string_random(), parameter_type, state);
simple.set_enabled(is_enabled);
// Assign action to the group
let group = GString::from(group);
// Return new Action
Self { group, simple }
}
// Getters // Getters
pub fn detailed_name(&self) -> GString { pub fn detailed_name(&self) -> GString {
gformat!("{}.{}", self.group, self.simple.name()) // @TODO find the way to ident parent group gformat!("{}.{}", self.group, self.simple.name()) // @TODO find the way to ident parent group

View File

@ -11,7 +11,7 @@ use window::Window;
use adw::ApplicationWindow; use adw::ApplicationWindow;
use gtk::{ use gtk::{
gio::{Cancellable, File, SimpleAction}, gio::{Cancellable, File, SimpleAction},
prelude::GtkWindowExt, prelude::{ActionExt, GtkWindowExt},
FileLauncher, FileLauncher,
}; };
use sqlite::Transaction; use sqlite::Transaction;
@ -174,8 +174,14 @@ impl Browser {
action_page_reload.connect_activate({ action_page_reload.connect_activate({
let window = window.clone(); let window = window.clone();
move |_, _| { move |this, _| {
window.tab_page_navigation_reload(); let page_position = this
.state()
.expect("Page position required for reload action")
.get::<i32>()
.expect("Parameter does not match `i32`");
window.tab_page_navigation_reload(page_position);
} }
}); });

View File

@ -92,8 +92,8 @@ impl Window {
self.tab.page_navigation_history_forward(); self.tab.page_navigation_history_forward();
} }
pub fn tab_page_navigation_reload(&self) { pub fn tab_page_navigation_reload(&self, page_position: i32) {
self.tab.page_navigation_reload(); self.tab.page_navigation_reload(page_position);
} }
pub fn tab_close(&self) { pub fn tab_close(&self) {

View File

@ -8,9 +8,9 @@ use widget::Widget;
use adw::TabView; use adw::TabView;
use gtk::{ use gtk::{
gio::SimpleAction, gio::{Menu, SimpleAction},
glib::{uuid_string_random, GString, Propagation}, glib::{gformat, uuid_string_random, GString, Propagation},
prelude::StaticVariantType, prelude::{ActionExt, StaticVariantType, ToVariant},
}; };
use sqlite::Transaction; use sqlite::Transaction;
use std::{cell::RefCell, collections::HashMap, sync::Arc}; use std::{cell::RefCell, collections::HashMap, sync::Arc};
@ -48,10 +48,51 @@ impl Tab {
// Init empty HashMap index as no tabs appended yet // Init empty HashMap index as no tabs appended yet
let index = Arc::new(RefCell::new(HashMap::new())); let index = Arc::new(RefCell::new(HashMap::new()));
// @TODO move to mod
let menu = Menu::new();
menu.append(
Some("Reload"),
Some(&gformat!("win.{}", action_page_reload.name())),
); // @TODO resolve namespace outside
// Init widget // Init widget
let widget = Arc::new(Widget::new(action_tab_open.clone())); let widget = Arc::new(Widget::new(&menu));
// Init events // Init events
// Setup actions for context menu
widget.gobject().connect_setup_menu({
let action_page_reload = action_page_reload.clone();
move |tab_view, tab_page| {
// Enable actions by default
action_page_reload.set_enabled(true);
match tab_page {
// Menu opened:
// setup actions to operate with page selected only
Some(this) => {
let position = tab_view.page_position(this).to_variant();
action_page_reload.change_state(&position);
}
// Menu closed:
// return actions to default values
None => match tab_view.selected_page() {
Some(selected) => {
// Get position of page selected
let position = tab_view.page_position(&selected).to_variant();
// Update related actions
action_page_reload.change_state(&position);
}
// No selected page found, disable related actions
None => action_page_reload.set_enabled(false),
},
}
}
});
widget.gobject().connect_close_page({ widget.gobject().connect_close_page({
let index = index.clone(); let index = index.clone();
move |_, item| { move |_, item| {
@ -201,8 +242,8 @@ impl Tab {
} }
} }
pub fn page_navigation_reload(&self) { pub fn page_navigation_reload(&self, page_position: i32) {
if let Some(id) = self.widget.current_page_keyword() { if let Some(id) = self.widget.gobject().nth_page(page_position).keyword() {
if let Some(item) = self.index.borrow().get(&id) { if let Some(item) = self.index.borrow().get(&id) {
item.page_navigation_reload(); item.page_navigation_reload();
} }

View File

@ -1,36 +1,37 @@
use adw::TabView; use adw::TabView;
use gtk::{ use gtk::{
gio::{Icon, SimpleAction, SimpleActionGroup}, gio::{Icon, MenuModel},
glib::{uuid_string_random, GString}, glib::GString,
prelude::{ActionMapExt, WidgetExt}, prelude::IsA,
}; };
/// Currently used as the indicator for pinned tabs
const DEFAULT_TAB_ICON: &str = "view-pin-symbolic";
/// Wrapper for [TabView](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.TabView.html) GObject
pub struct Widget { pub struct Widget {
gobject: TabView, gobject: TabView,
} }
impl Widget { impl Widget {
// Construct // Construct
pub fn new(action_page_new: SimpleAction) -> Self { pub fn new(menu_model: &impl IsA<MenuModel>) -> Self {
// Init additional action group
let action_group = SimpleActionGroup::new();
action_group.add_action(&action_page_new);
// Init gobject // Init gobject
let gobject = TabView::new(); let gobject = TabView::builder().menu_model(menu_model).build();
// Change default icon visible for tabs pinned // Change default icon (if available in the system icon set)
if let Ok(default_icon) = Icon::for_string("view-pin-symbolic") { // * visible for pinned tabs only
// * @TODO not default GTK behavior, make this feature optional
if let Ok(default_icon) = Icon::for_string(DEFAULT_TAB_ICON) {
gobject.set_default_icon(&default_icon); gobject.set_default_icon(&default_icon);
} }
// Create new group for actions // Done
gobject.insert_action_group(&uuid_string_random(), Some(&action_group));
Self { gobject } Self { gobject }
} }
// Actions // Actions
pub fn close(&self) { pub fn close(&self) {
if let Some(selected_page) = self.gobject.selected_page() { if let Some(selected_page) = self.gobject.selected_page() {
self.gobject.close_page(&selected_page); self.gobject.close_page(&selected_page);
@ -46,6 +47,7 @@ impl Widget {
} }
// Getters // Getters
pub fn current_page_keyword(&self) -> Option<GString> { pub fn current_page_keyword(&self) -> Option<GString> {
let page = self.gobject.selected_page()?; let page = self.gobject.selected_page()?;
let id = page.keyword()?; let id = page.keyword()?;