diff --git a/data/resources/style.css b/data/resources/style.css index b2abfdf2..c836ea5a 100644 --- a/data/resources/style.css +++ b/data/resources/style.css @@ -245,7 +245,7 @@ session-verification .text-button { background: none; } -sidebar-row > * { +sidebar-row > *:not(popover) { margin: 0 6px; padding: 9px; border-radius: 6px; @@ -257,29 +257,29 @@ sidebar-row > * { margin-top: 2px; } -sidebar-row:focus > * { +sidebar-row:focus > *:not(popover) { outline-color: alpha(@accent_color, 0.5); outline-width: 2px; outline-offset: -2px; } -sidebar-row:not(.drop-mode) > *:hover { +sidebar-row:not(.drop-mode) > *:not(popover):hover { background-color: alpha(currentColor, 0.07); } -.sidebar-list row:active sidebar-row > * { +.sidebar-list row:active sidebar-row > *:not(popover) { background-color: alpha(currentColor, 0.16); } -.sidebar-list row:selected sidebar-row > * { +.sidebar-list row:selected sidebar-row > *:not(popover) { background-color: alpha(currentColor, 0.1); } -.sidebar-list row:selected sidebar-row:not(.drop-mode) > *:hover { +.sidebar-list row:selected sidebar-row:not(.drop-mode) > *:not(popover):hover { background-color: alpha(currentColor, 0.13); } -.sidebar-list row:selected:active sidebar-row > * { +.sidebar-list row:selected:active sidebar-row > *:not(popover) { background-color: alpha(currentColor, 0.19); } @@ -331,11 +331,11 @@ sidebar-row.drag > * { opacity: 0.6; } -sidebar-row.drop-disabled > * { +sidebar-row.drop-disabled > *:not(popover) { opacity: 0.6; } -sidebar-row.drop-empty > * { +sidebar-row.drop-empty > *:not(popover) { color: @accent_color; } diff --git a/po/POTFILES.in b/po/POTFILES.in index 3cca51bf..0b45dd38 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -117,6 +117,7 @@ src/session/view/media_viewer.ui src/session/view/room_creation.rs src/session/view/room_creation.ui src/session/view/sidebar/category_row.rs +src/session/view/sidebar/mod.rs src/session/view/sidebar/mod.ui src/session/view/sidebar/room_row.rs src/session/view/sidebar/row.rs diff --git a/src/components/context_menu_bin.rs b/src/components/context_menu_bin.rs index fa731d6c..d2c6246b 100644 --- a/src/components/context_menu_bin.rs +++ b/src/components/context_menu_bin.rs @@ -2,7 +2,7 @@ use adw::subclass::prelude::*; use gtk::{gdk, glib, glib::clone, prelude::*, CompositeTemplate}; mod imp { - use std::cell::RefCell; + use std::cell::{Cell, RefCell}; use glib::{subclass::InitializingObject, SignalHandlerId}; @@ -31,6 +31,11 @@ mod imp { pub click_gesture: TemplateChild, #[template_child] pub long_press_gesture: TemplateChild, + /// Whether this widget has a context menu. + /// + /// If this is set to `false`, all the actions will be disabled. + #[property(get, set = Self::set_has_context_menu, explicit_notify)] + pub has_context_menu: Cell, /// The popover displaying the context menu. #[property(get, set = Self::set_popover, explicit_notify, nullable)] pub popover: RefCell>, @@ -83,9 +88,11 @@ mod imp { self.long_press_gesture .connect_pressed(clone!(@weak obj => move |gesture, x, y| { - gesture.set_state(gtk::EventSequenceState::Claimed); - gesture.reset(); - obj.open_menu_at(x as i32, y as i32); + if obj.has_context_menu() { + gesture.set_state(gtk::EventSequenceState::Claimed); + gesture.reset(); + obj.open_menu_at(x as i32, y as i32); + } })); self.click_gesture.connect_released( @@ -94,8 +101,10 @@ mod imp { return; } - gesture.set_state(gtk::EventSequenceState::Claimed); - obj.open_menu_at(x as i32, y as i32); + if obj.has_context_menu() { + gesture.set_state(gtk::EventSequenceState::Claimed); + obj.open_menu_at(x as i32, y as i32); + } }), ); self.parent_constructed(); @@ -116,6 +125,22 @@ mod imp { impl BinImpl for ContextMenuBin {} impl ContextMenuBin { + /// Set whether this widget has a context menu. + fn set_has_context_menu(&self, has_context_menu: bool) { + if self.has_context_menu.get() == has_context_menu { + return; + } + + self.has_context_menu.set(has_context_menu); + + let obj = self.obj(); + obj.update_property(&[gtk::accessible::Property::HasPopup(has_context_menu)]); + obj.action_set_enabled("context-menu.activate", has_context_menu); + obj.action_set_enabled("context-menu.close", has_context_menu); + + obj.notify_has_context_menu(); + } + /// Set the popover displaying the context menu. fn set_popover(&self, popover: Option) { if *self.popover.borrow() == popover { @@ -150,13 +175,17 @@ mod imp { } glib::wrapper! { - /// A Bin widget that adds a context menu. + /// A Bin widget that can have a context menu. pub struct ContextMenuBin(ObjectSubclass) @extends gtk::Widget, adw::Bin, @implements gtk::Accessible; } impl ContextMenuBin { fn open_menu_at(&self, x: i32, y: i32) { + if !self.has_context_menu() { + return; + } + self.menu_opened(); if let Some(popover) = self.popover() { @@ -167,6 +196,12 @@ impl ContextMenuBin { } pub trait ContextMenuBinExt: 'static { + /// Whether this widget has a context menu. + fn has_context_menu(&self) -> bool; + + /// Set whether this widget has a context menu. + fn set_has_context_menu(&self, has_context_menu: bool); + /// Get the `PopoverMenu` used in the context menu. fn popover(&self) -> Option; @@ -178,6 +213,14 @@ pub trait ContextMenuBinExt: 'static { } impl> ContextMenuBinExt for O { + fn has_context_menu(&self) -> bool { + self.upcast_ref().has_context_menu() + } + + fn set_has_context_menu(&self, has_context_menu: bool) { + self.upcast_ref().set_has_context_menu(has_context_menu); + } + fn popover(&self) -> Option { self.upcast_ref().popover() } diff --git a/src/session/view/content/room_history/item_row.rs b/src/session/view/content/room_history/item_row.rs index 5dcd6d16..6692615f 100644 --- a/src/session/view/content/room_history/item_row.rs +++ b/src/session/view/content/room_history/item_row.rs @@ -57,8 +57,11 @@ mod imp { impl ObjectImpl for ItemRow { fn constructed(&self) { self.parent_constructed(); + let obj = self.obj(); + + obj.set_has_context_menu(true); - self.obj().connect_parent_notify(|obj| { + obj.connect_parent_notify(|obj| { obj.update_highlight(); }); } diff --git a/src/session/view/sidebar/category_row.rs b/src/session/view/sidebar/category_row.rs index 2fcf665e..933a1edf 100644 --- a/src/session/view/sidebar/category_row.rs +++ b/src/session/view/sidebar/category_row.rs @@ -57,7 +57,15 @@ mod imp { } #[glib::derived_properties] - impl ObjectImpl for CategoryRow {} + impl ObjectImpl for CategoryRow { + fn constructed(&self) { + self.parent_constructed(); + + self.obj().connect_parent_notify(|obj| { + obj.set_expanded_accessibility_state(obj.expanded()); + }); + } + } impl WidgetImpl for CategoryRow {} impl BinImpl for CategoryRow {} diff --git a/src/session/view/sidebar/mod.rs b/src/session/view/sidebar/mod.rs index 34d7f9c8..9a3f5d57 100644 --- a/src/session/view/sidebar/mod.rs +++ b/src/session/view/sidebar/mod.rs @@ -5,6 +5,7 @@ mod row; mod verification_row; use adw::{prelude::*, subclass::prelude::*}; +use gettextrs::gettext; use gtk::{gio, glib, glib::clone, CompositeTemplate}; use tracing::error; @@ -288,14 +289,18 @@ impl Sidebar { self.notify_drop_active_target_category_type(); } + /// The shared popover for a room row in the sidebar. pub fn room_row_popover(&self) -> >k::PopoverMenu { let imp = self.imp(); imp.room_row_popover.get_or_init(|| { - gtk::PopoverMenu::builder() + let popover = gtk::PopoverMenu::builder() .menu_model(&*imp.room_row_menu) .has_arrow(false) .halign(gtk::Align::Start) - .build() + .build(); + popover.update_property(&[gtk::accessible::Property::Label(&gettext("Context Menu"))]); + + popover }) } } diff --git a/src/session/view/sidebar/mod.ui b/src/session/view/sidebar/mod.ui index e4da116b..6638f225 100644 --- a/src/session/view/sidebar/mod.ui +++ b/src/session/view/sidebar/mod.ui @@ -31,51 +31,51 @@ _Accept room-row.accept-invite - action-disabled + action-missing _Reject room-row.reject-invite - action-disabled + action-missing
Move to _Favorites room-row.set-favorite - action-disabled + action-missing Move to _Rooms room-row.set-normal - action-disabled + action-missing Move to Low _Priority room-row.set-lowpriority - action-disabled + action-missing
_Leave Room room-row.leave - action-disabled + action-missing Re_join Room room-row.join - action-disabled + action-missing _Forget Room room-row.forget - action-disabled + action-missing