[fractal/fractal-next] sidebar: Add Explore entry
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] sidebar: Add Explore entry
- Date: Sat, 12 Jun 2021 14:09:45 +0000 (UTC)
commit bd13ae4ef233c6065972818725ba0fb6d95d401b
Author: Julian Sparber <julian sparber net>
Date: Thu Jun 3 19:22:59 2021 +0200
sidebar: Add Explore entry
.../icons/scalable/status/explore-symbolic.svg | 151 ++++++++++++++++++++
data/resources/resources.gresource.xml | 2 +
data/resources/style.css | 5 +
data/resources/ui/session.ui | 2 +
data/resources/ui/sidebar-entry-row.ui | 36 +++++
po/POTFILES.in | 2 +
src/session/content/content.rs | 61 +++++++--
src/session/content/content_type.rs | 27 ++++
src/session/content/mod.rs | 2 +
src/session/mod.rs | 43 +++++-
src/session/sidebar/entry.rs | 109 +++++++++++++++
src/session/sidebar/entry_row.rs | 101 ++++++++++++++
src/session/sidebar/item_list.rs | 24 ++--
src/session/sidebar/mod.rs | 4 +
src/session/sidebar/row.rs | 17 ++-
src/session/sidebar/selection.rs | 152 +++++++++++++++------
src/session/sidebar/sidebar.rs | 44 +++++-
17 files changed, 714 insertions(+), 68 deletions(-)
---
diff --git a/data/resources/icons/scalable/status/explore-symbolic.svg
b/data/resources/icons/scalable/status/explore-symbolic.svg
new file mode 100644
index 00000000..3dac6a5e
--- /dev/null
+++ b/data/resources/icons/scalable/status/explore-symbolic.svg
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
+ <filter id="a" height="100%" width="100%" x="0%" y="0%">
+ <feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
+ </filter>
+ <mask id="b">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/>
+ </g>
+ </mask>
+ <clipPath id="c">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="d">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
+ </g>
+ </mask>
+ <clipPath id="e">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="f">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
+ </g>
+ </mask>
+ <clipPath id="g">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="h">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
+ </g>
+ </mask>
+ <clipPath id="i">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="j">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
+ </g>
+ </mask>
+ <clipPath id="k">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="l">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
+ </g>
+ </mask>
+ <clipPath id="m">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="n">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/>
+ </g>
+ </mask>
+ <clipPath id="o">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="p">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/>
+ </g>
+ </mask>
+ <clipPath id="q">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="r">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/>
+ </g>
+ </mask>
+ <clipPath id="s">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="t">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.4"/>
+ </g>
+ </mask>
+ <clipPath id="u">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="v">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.4"/>
+ </g>
+ </mask>
+ <clipPath id="w">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="x">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/>
+ </g>
+ </mask>
+ <clipPath id="y">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <mask id="z">
+ <g filter="url(#a)">
+ <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/>
+ </g>
+ </mask>
+ <clipPath id="A">
+ <path d="m 0 0 h 1024 v 800 h -1024 z"/>
+ </clipPath>
+ <g clip-path="url(#c)" mask="url(#b)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 562.460938 212.058594 h 10.449218 c -1.183594 0.492187 -1.296875 2.460937 0 3 h
-10.449218 z m 0 0" fill="#2e3436"/>
+ </g>
+ <path d="m 8 1 c -0.207031 0 -0.390625 0.125 -0.46875 0.320312 l -1.726562 4.488282 l -4.484376 1.722656
c -0.425781 0.167969 -0.425781 0.769531 0 0.9375 l 4.484376 1.722656 l 1.726562 4.488282 c 0.167969 0.425781
0.769531 0.425781 0.9375 0 l 1.726562 -4.488282 l 4.484376 -1.722656 c 0.425781 -0.167969 0.425781 -0.769531
0 -0.9375 l -4.484376 -1.722656 l -1.726562 -4.488282 c -0.074219 -0.191406 -0.261719 -0.320312 -0.46875
-0.320312 z m 0 6 c 0.550781 0 1 0.449219 1 1 s -0.449219 1 -1 1 s -1 -0.449219 -1 -1 s 0.449219 -1 1 -1 z m
0 0" fill="#2e3436" fill-rule="evenodd"/>
+ <path d="m 3.480469 3 c -0.363281 0.011719 -0.589844 0.398438 -0.429688 0.722656 l 0.871094 1.738282 l
1.109375 -0.429688 l 0.429688 -1.109375 l -1.738282 -0.871094 c -0.074218 -0.035156 -0.15625 -0.054687
-0.242187 -0.050781 z m 9.039062 0 c -0.085937 -0.003906 -0.167969 0.015625 -0.242187 0.050781 l -1.738282
0.871094 l 0.429688 1.109375 l 1.109375 0.429688 l 0.871094 -1.738282 c 0.160156 -0.324218 -0.066407
-0.710937 -0.429688 -0.722656 z m -8.597656 7.539062 l -0.871094 1.738282 c -0.210937 0.429687 0.242188
0.882812 0.671875 0.671875 l 1.738282 -0.871094 l -0.429688 -1.109375 z m 8.15625 0 l -1.109375 0.429688 l
-0.429688 1.109375 l 1.738282 0.871094 c 0.429687 0.210937 0.882812 -0.242188 0.671875 -0.671875 z m 0 0"
fill="#2e3436" fill-rule="evenodd"/>
+ <g clip-path="url(#e)" mask="url(#d)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 16 632 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
+ </g>
+ <g clip-path="url(#g)" mask="url(#f)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 17 631 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
+ </g>
+ <g clip-path="url(#i)" mask="url(#h)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 18 634 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
+ </g>
+ <g clip-path="url(#k)" mask="url(#j)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 16 634 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
+ </g>
+ <g clip-path="url(#m)" mask="url(#l)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 17 635 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
+ </g>
+ <g clip-path="url(#o)" mask="url(#n)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 19 635 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/>
+ </g>
+ <g clip-path="url(#q)" mask="url(#p)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 136 660 v 7 h 7 v -7 z m 0 0" fill="#2e3436"/>
+ </g>
+ <g clip-path="url(#s)" mask="url(#r)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 199 642 h 3 v 12 h -3 z m 0 0" fill="#2e3436"/>
+ </g>
+ <g clip-path="url(#u)" mask="url(#t)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 209.5 144.160156 c 0.277344 0 0.5 0.222656 0.5 0.5 v 1 c 0 0.277344 -0.222656 0.5 -0.5
0.5 s -0.5 -0.222656 -0.5 -0.5 v -1 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0" fill="#2e3436"/>
+ </g>
+ <g clip-path="url(#w)" mask="url(#v)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 206.5 144.160156 c 0.277344 0 0.5 0.222656 0.5 0.5 v 1 c 0 0.277344 -0.222656 0.5 -0.5
0.5 s -0.5 -0.222656 -0.5 -0.5 v -1 c 0 -0.277344 0.222656 -0.5 0.5 -0.5 z m 0 0" fill="#2e3436"/>
+ </g>
+ <g clip-path="url(#y)" mask="url(#x)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 229.5 143.160156 c -0.546875 0 -1 0.457032 -1 1 c 0 0.546875 0.453125 1 1 1 s 1 -0.453125
1 -1 c 0 -0.542968 -0.453125 -1 -1 -1 z m 0 0" fill="#2e3436"/>
+ </g>
+ <g clip-path="url(#A)" mask="url(#z)" transform="matrix(1 0 0 1 -600 -80)">
+ <path d="m 226.453125 143.160156 c -0.519531 0 -0.953125 0.433594 -0.953125 0.953125 v 0.09375 c 0
0.519531 0.433594 0.953125 0.953125 0.953125 h 0.09375 c 0.519531 0 0.953125 -0.433594 0.953125 -0.953125 v
-0.09375 c 0 -0.519531 -0.433594 -0.953125 -0.953125 -0.953125 z m 0 0" fill="#2e3436"/>
+ </g>
+</svg>
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index 4e2683c3..ebcba03e 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -17,6 +17,7 @@
<file compressed="true" preprocess="xml-stripblanks" alias="sidebar.ui">ui/sidebar.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="sidebar-item.ui">ui/sidebar-item.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="sidebar-category-row.ui">ui/sidebar-category-row.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks"
alias="sidebar-entry-row.ui">ui/sidebar-entry-row.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="sidebar-room-row.ui">ui/sidebar-room-row.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="window.ui">ui/window.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="context-menu-bin.ui">ui/context-menu-bin.ui</file>
@@ -27,6 +28,7 @@
<file compressed="true">style.css</file>
<file preprocess="xml-stripblanks">icons/scalable/actions/send-symbolic.svg</file>
<file preprocess="xml-stripblanks">icons/scalable/status/welcome.svg</file>
+ <file preprocess="xml-stripblanks">icons/scalable/status/explore-symbolic.svg</file>
</gresource>
</gresources>
diff --git a/data/resources/style.css b/data/resources/style.css
index 91f3b54d..ee1a5c59 100644
--- a/data/resources/style.css
+++ b/data/resources/style.css
@@ -46,6 +46,11 @@ headerbar.flat {
font-weight: bold;
}
+.sidebar .entry {
+ margin-top: 4px;
+ font-weight: bold;
+}
+
.sidebar .category image.arrow {
transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
diff --git a/data/resources/ui/session.ui b/data/resources/ui/session.ui
index 590cf2cc..363738c9 100644
--- a/data/resources/ui/session.ui
+++ b/data/resources/ui/session.ui
@@ -51,12 +51,14 @@
<property name="compact" bind-source="content" bind-property="folded"
bind-flags="sync-create"/>
<property name="room-list" bind-source="Session" bind-property="room-list"
bind-flags="sync-create"/>
<property name="selected-room" bind-source="Session" bind-property="selected-room"
bind-flags="sync-create | bidirectional"/>
+ <property name="selected-type" bind-source="Session"
bind-property="selected-content-type" bind-flags="sync-create | bidirectional"/>
</object>
</child>
<child>
<object class="Content">
<property name="compact" bind-source="content" bind-property="folded"
bind-flags="sync-create"/>
<property name="room" bind-source="Session" bind-property="selected-room"
bind-flags="sync-create | bidirectional"/>
+ <property name="content-type" bind-source="Session"
bind-property="selected-content-type" bind-flags="sync-create | bidirectional"/>
<property name="error-list">error_list</property>
</object>
</child>
diff --git a/data/resources/ui/sidebar-entry-row.ui b/data/resources/ui/sidebar-entry-row.ui
new file mode 100644
index 00000000..4082eea1
--- /dev/null
+++ b/data/resources/ui/sidebar-entry-row.ui
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="SidebarEntryRow" parent="AdwBin">
+ <style>
+ <class name="entry-row"/>
+ </style>
+ <child>
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">explore2-symbolic</property>
+ <binding name="icon-name">
+ <lookup name="icon-name" type="Entry">
+ <lookup name="entry">SidebarEntryRow</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="ellipsize">end</property>
+ <binding name="label">
+ <lookup name="display-name" type="Entry">
+ <lookup name="entry">SidebarEntryRow</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 28cd433e..41d6c374 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -22,6 +22,7 @@ data/resources/ui/in-app-notification.ui
data/resources/ui/session.ui
data/resources/ui/shortcuts.ui
data/resources/ui/sidebar-category-row.ui
+data/resources/ui/sidebar-entry-row.ui
data/resources/ui/sidebar-item.ui
data/resources/ui/sidebar-room-row.ui
data/resources/ui/sidebar.ui
@@ -64,6 +65,7 @@ src/session/room/mod.rs
src/session/room/room.rs
src/session/room/timeline.rs
src/session/sidebar/category_row.rs
+src/session/sidebar/entry.rs
src/session/sidebar/mod.rs
src/session/sidebar/room_row.rs
src/session/sidebar/row.rs
diff --git a/src/session/content/content.rs b/src/session/content/content.rs
index d7dd8166..ac16a977 100644
--- a/src/session/content/content.rs
+++ b/src/session/content/content.rs
@@ -1,4 +1,5 @@
use crate::session::{
+ content::ContentType,
content::Invite,
content::RoomHistory,
room::{Room, RoomType},
@@ -16,6 +17,7 @@ mod imp {
pub struct Content {
pub compact: Cell<bool>,
pub room: RefCell<Option<Room>>,
+ pub content_type: Cell<ContentType>,
pub error_list: RefCell<Option<gio::ListStore>>,
pub category_handler: RefCell<Option<SignalHandlerId>>,
#[template_child]
@@ -39,7 +41,7 @@ mod imp {
klass.set_accessible_role(gtk::AccessibleRole::Group);
klass.install_action("content.go-back", None, move |widget, _, _| {
- widget.set_room(None);
+ widget.set_content_type(ContentType::None);
});
}
@@ -74,6 +76,14 @@ mod imp {
gio::ListStore::static_type(),
glib::ParamFlags::READWRITE,
),
+ glib::ParamSpec::new_enum(
+ "content-type",
+ "Content Type",
+ "The type of content currently displayed",
+ ContentType::static_type(),
+ ContentType::default() as i32,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
]
});
@@ -99,6 +109,7 @@ mod imp {
"error-list" => {
self.error_list.replace(value.get().unwrap());
}
+ "content-type" => obj.set_content_type(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -108,6 +119,7 @@ mod imp {
"compact" => self.compact.get().to_value(),
"room" => obj.room().to_value(),
"error-list" => self.error_list.borrow().to_value(),
+ "content-type" => obj.content_type().to_value(),
_ => unimplemented!(),
}
}
@@ -127,6 +139,24 @@ impl Content {
glib::Object::new(&[]).expect("Failed to create Content")
}
+ pub fn content_type(&self) -> ContentType {
+ let priv_ = imp::Content::from_instance(self);
+ priv_.content_type.get()
+ }
+
+ pub fn set_content_type(&self, content_type: ContentType) {
+ let priv_ = imp::Content::from_instance(self);
+
+ if self.content_type() == content_type {
+ return;
+ }
+
+ priv_.content_type.set(content_type);
+ self.set_visible_child();
+
+ self.notify("content-type");
+ }
+
pub fn set_room(&self, room: Option<Room>) {
let priv_ = imp::Content::from_instance(self);
@@ -143,17 +173,16 @@ impl Content {
if let Some(ref room) = room {
let handler_id = room.connect_notify_local(
Some("category"),
- clone!(@weak self as obj => move |room, _| {
- obj.set_visible_child(room);
+ clone!(@weak self as obj => move |_, _| {
+ obj.set_visible_child();
}),
);
- self.set_visible_child(&room);
priv_.category_handler.replace(Some(handler_id));
}
priv_.room.replace(room);
-
+ self.set_visible_child();
self.notify("room");
}
@@ -162,13 +191,25 @@ impl Content {
priv_.room.borrow().clone()
}
- fn set_visible_child(&self, room: &Room) {
+ fn set_visible_child(&self) {
let priv_ = imp::Content::from_instance(self);
- if room.category() == RoomType::Invited {
- priv_.stack.set_visible_child(&*priv_.invite);
- } else {
- priv_.stack.set_visible_child(&*priv_.room_history);
+ match self.content_type() {
+ ContentType::None => {
+ //TODO: display an empty state
+ }
+ ContentType::Room => {
+ if let Some(room) = &*priv_.room.borrow() {
+ if room.category() == RoomType::Invited {
+ priv_.stack.set_visible_child(&*priv_.invite);
+ } else {
+ priv_.stack.set_visible_child(&*priv_.room_history);
+ }
+ }
+ }
+ ContentType::Explore => {
+ todo!("Display explore");
+ }
}
}
}
diff --git a/src/session/content/content_type.rs b/src/session/content/content_type.rs
new file mode 100644
index 00000000..50eff2a5
--- /dev/null
+++ b/src/session/content/content_type.rs
@@ -0,0 +1,27 @@
+use gettextrs::gettext;
+use gtk::glib;
+
+#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy, glib::GEnum)]
+#[repr(u32)]
+#[genum(type_name = "ContentType")]
+pub enum ContentType {
+ None = 0,
+ Explore = 1,
+ Room = 2,
+}
+
+impl Default for ContentType {
+ fn default() -> Self {
+ ContentType::None
+ }
+}
+
+impl ToString for ContentType {
+ fn to_string(&self) -> String {
+ match self {
+ ContentType::None => gettext("No selection"),
+ ContentType::Explore => gettext("Explore"),
+ ContentType::Room => gettext("Room"),
+ }
+ }
+}
diff --git a/src/session/content/mod.rs b/src/session/content/mod.rs
index 3109a2ed..0de3f250 100644
--- a/src/session/content/mod.rs
+++ b/src/session/content/mod.rs
@@ -1,4 +1,5 @@
mod content;
+mod content_type;
mod divider_row;
mod invite;
mod item_row;
@@ -8,6 +9,7 @@ mod room_history;
mod state_row;
pub use self::content::Content;
+pub use self::content_type::ContentType;
use self::divider_row::DividerRow;
use self::invite::Invite;
use self::item_row::ItemRow;
diff --git a/src/session/mod.rs b/src/session/mod.rs
index 470a5006..07c13f56 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -20,6 +20,7 @@ use crate::utils::do_async;
use crate::Error;
use crate::RUNTIME;
+use crate::session::content::ContentType;
use adw;
use adw::subclass::prelude::BinImpl;
use gtk::subclass::prelude::*;
@@ -41,7 +42,7 @@ mod imp {
use super::*;
use glib::subclass::{InitializingObject, Signal};
use once_cell::sync::{Lazy, OnceCell};
- use std::cell::RefCell;
+ use std::cell::{Cell, RefCell};
#[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/org/gnome/FractalNext/session.ui")]
@@ -58,6 +59,7 @@ mod imp {
pub room_list: OnceCell<RoomList>,
pub user: OnceCell<User>,
pub selected_room: RefCell<Option<Room>>,
+ pub selected_content_type: Cell<ContentType>,
pub is_ready: OnceCell<bool>,
}
@@ -98,6 +100,14 @@ mod imp {
Room::static_type(),
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
+ glib::ParamSpec::new_enum(
+ "selected-content-type",
+ "Selected Content Type",
+ "The current content type selected",
+ ContentType::static_type(),
+ ContentType::default() as i32,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
glib::ParamSpec::new_object(
"user",
"User",
@@ -123,6 +133,7 @@ mod imp {
let selected_room = value.get().unwrap();
obj.set_selected_room(selected_room);
}
+ "selected-content-type" => obj.set_selected_content_type(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -132,6 +143,7 @@ mod imp {
"room-list" => obj.room_list().to_value(),
"selected-room" => obj.selected_room().to_value(),
"user" => obj.user().to_value(),
+ "selected-content-type" => obj.selected_content_type().to_value(),
_ => unimplemented!(),
}
}
@@ -157,6 +169,29 @@ impl Session {
glib::Object::new(&[]).expect("Failed to create Session")
}
+ pub fn selected_content_type(&self) -> ContentType {
+ let priv_ = imp::Session::from_instance(self);
+ priv_.selected_content_type.get()
+ }
+
+ pub fn set_selected_content_type(&self, selected_type: ContentType) {
+ let priv_ = imp::Session::from_instance(self);
+
+ if self.selected_content_type() == selected_type {
+ return;
+ }
+
+ if selected_type == ContentType::None {
+ priv_.content.navigate(adw::NavigationDirection::Back);
+ } else {
+ priv_.content.navigate(adw::NavigationDirection::Forward);
+ }
+
+ priv_.selected_content_type.set(selected_type);
+
+ self.notify("selected-content-type");
+ }
+
pub fn selected_room(&self) -> Option<Room> {
let priv_ = imp::Session::from_instance(self);
priv_.selected_room.borrow().clone()
@@ -169,12 +204,6 @@ impl Session {
return;
}
- if selected_room.is_some() {
- priv_.content.navigate(adw::NavigationDirection::Forward);
- } else {
- priv_.content.navigate(adw::NavigationDirection::Back);
- }
-
priv_.selected_room.replace(selected_room);
self.notify("selected-room");
diff --git a/src/session/sidebar/entry.rs b/src/session/sidebar/entry.rs
new file mode 100644
index 00000000..0aea94ad
--- /dev/null
+++ b/src/session/sidebar/entry.rs
@@ -0,0 +1,109 @@
+use gtk::{glib, prelude::*, subclass::prelude::*};
+
+use crate::session::content::ContentType;
+
+mod imp {
+ use std::cell::{Cell, RefCell};
+
+ use super::*;
+
+ #[derive(Debug, Default)]
+ pub struct Entry {
+ pub type_: Cell<ContentType>,
+ pub display_name: RefCell<Option<String>>,
+ pub icon_name: RefCell<Option<String>>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for Entry {
+ const NAME: &'static str = "Entry";
+ type Type = super::Entry;
+ type ParentType = glib::Object;
+ }
+
+ impl ObjectImpl for Entry {
+ fn properties() -> &'static [glib::ParamSpec] {
+ use once_cell::sync::Lazy;
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::new_enum(
+ "type",
+ "Type",
+ "The type of this category",
+ ContentType::static_type(),
+ ContentType::default() as i32,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+ ),
+ glib::ParamSpec::new_string(
+ "display-name",
+ "Display Name",
+ "The display name of this Entry",
+ None,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
+ glib::ParamSpec::new_string(
+ "icon-name",
+ "Icon Name",
+ "The icon name used for this Entry",
+ None,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
+ ]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.name() {
+ "type" => {
+ self.type_.set(value.get().unwrap());
+ }
+ "display-name" => {
+ let _ = self.display_name.replace(value.get().unwrap());
+ }
+ "icon-name" => {
+ let _ = self.icon_name.replace(value.get().unwrap());
+ }
+ _ => unimplemented!(),
+ }
+ }
+
+ fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "type" => obj.type_().to_value(),
+ "display-name" => obj.type_().to_string().to_value(),
+ "icon-name" => obj.icon_name().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+ }
+}
+
+glib::wrapper! {
+ pub struct Entry(ObjectSubclass<imp::Entry>);
+}
+
+impl Entry {
+ pub fn new(type_: ContentType) -> Self {
+ glib::Object::new(&[("type", &type_)]).expect("Failed to create Entry")
+ }
+
+ pub fn type_(&self) -> ContentType {
+ let priv_ = imp::Entry::from_instance(self);
+ priv_.type_.get()
+ }
+
+ pub fn icon_name(&self) -> Option<&str> {
+ match self.type_() {
+ ContentType::Explore => Some("explore-symbolic"),
+ _ => None,
+ }
+ }
+}
diff --git a/src/session/sidebar/entry_row.rs b/src/session/sidebar/entry_row.rs
new file mode 100644
index 00000000..bf7faa0c
--- /dev/null
+++ b/src/session/sidebar/entry_row.rs
@@ -0,0 +1,101 @@
+use adw;
+use adw::subclass::prelude::BinImpl;
+use gtk::subclass::prelude::*;
+use gtk::{self, prelude::*};
+use gtk::{glib, CompositeTemplate};
+
+use crate::session::sidebar::Entry;
+
+mod imp {
+ use super::*;
+ use glib::subclass::InitializingObject;
+ use std::cell::RefCell;
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/FractalNext/sidebar-entry-row.ui")]
+ pub struct EntryRow {
+ pub entry: RefCell<Option<Entry>>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for EntryRow {
+ const NAME: &'static str = "SidebarEntryRow";
+ type Type = super::EntryRow;
+ type ParentType = adw::Bin;
+
+ fn class_init(klass: &mut Self::Class) {
+ Self::bind_template(klass);
+ }
+
+ fn instance_init(obj: &InitializingObject<Self>) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for EntryRow {
+ fn properties() -> &'static [glib::ParamSpec] {
+ use once_cell::sync::Lazy;
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::new_object(
+ "entry",
+ "Entry",
+ "The entry of this row",
+ Entry::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.name() {
+ "entry" => obj.set_entry(value.get().unwrap()),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "entry" => obj.entry().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+ }
+
+ impl WidgetImpl for EntryRow {}
+ impl BinImpl for EntryRow {}
+}
+
+glib::wrapper! {
+ pub struct EntryRow(ObjectSubclass<imp::EntryRow>)
+ @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
+}
+
+impl EntryRow {
+ pub fn new() -> Self {
+ glib::Object::new(&[]).expect("Failed to create EntryRow")
+ }
+
+ pub fn entry(&self) -> Option<Entry> {
+ let priv_ = imp::EntryRow::from_instance(&self);
+ priv_.entry.borrow().clone()
+ }
+
+ pub fn set_entry(&self, entry: Option<Entry>) {
+ let priv_ = imp::EntryRow::from_instance(&self);
+
+ if self.entry() == entry {
+ return;
+ }
+
+ priv_.entry.replace(entry);
+ self.notify("entry");
+ }
+}
diff --git a/src/session/sidebar/item_list.rs b/src/session/sidebar/item_list.rs
index 0cd4a89d..1c0675b6 100644
--- a/src/session/sidebar/item_list.rs
+++ b/src/session/sidebar/item_list.rs
@@ -1,6 +1,11 @@
use gtk::{gio, glib, prelude::*, subclass::prelude::*};
-use crate::session::{room::RoomType, room_list::RoomList, sidebar::Category};
+use crate::session::{
+ content::ContentType,
+ room::RoomType,
+ room_list::RoomList,
+ sidebar::{Category, Entry},
+};
mod imp {
use once_cell::unsync::OnceCell;
@@ -9,7 +14,7 @@ mod imp {
#[derive(Debug, Default)]
pub struct ItemList {
- pub list: OnceCell<[Category; 5]>,
+ pub list: OnceCell<[glib::Object; 6]>,
}
#[glib::object_subclass]
@@ -24,7 +29,7 @@ mod imp {
impl ListModelImpl for ItemList {
fn item_type(&self, _list_model: &Self::Type) -> glib::Type {
- Category::static_type()
+ glib::Object::static_type()
}
fn n_items(&self, _list_model: &Self::Type) -> u32 {
self.list.get().map(|l| l.len()).unwrap_or(0) as u32
@@ -61,14 +66,15 @@ impl ItemList {
priv_
.list
.set([
- Category::new(RoomType::Invited, room_list),
- Category::new(RoomType::Favorite, room_list),
- Category::new(RoomType::Normal, room_list),
- Category::new(RoomType::LowPriority, room_list),
- Category::new(RoomType::Left, room_list),
+ Entry::new(ContentType::Explore).upcast::<glib::Object>(),
+ Category::new(RoomType::Invited, room_list).upcast::<glib::Object>(),
+ Category::new(RoomType::Favorite, room_list).upcast::<glib::Object>(),
+ Category::new(RoomType::Normal, room_list).upcast::<glib::Object>(),
+ Category::new(RoomType::LowPriority, room_list).upcast::<glib::Object>(),
+ Category::new(RoomType::Left, room_list).upcast::<glib::Object>(),
])
.unwrap();
- self.items_changed(0, 0, 5);
+ self.items_changed(0, 0, 6);
}
}
diff --git a/src/session/sidebar/mod.rs b/src/session/sidebar/mod.rs
index 0b298088..e9cc2def 100644
--- a/src/session/sidebar/mod.rs
+++ b/src/session/sidebar/mod.rs
@@ -1,5 +1,7 @@
mod category;
mod category_row;
+mod entry;
+mod entry_row;
mod item_list;
mod room_row;
mod row;
@@ -8,6 +10,8 @@ mod sidebar;
pub use self::category::Category;
use self::category_row::CategoryRow;
+pub use self::entry::Entry;
+use self::entry_row::EntryRow;
pub use self::item_list::ItemList;
use self::room_row::RoomRow;
use self::row::Row;
diff --git a/src/session/sidebar/row.rs b/src/session/sidebar/row.rs
index 3a4629b5..9ff8ed80 100644
--- a/src/session/sidebar/row.rs
+++ b/src/session/sidebar/row.rs
@@ -3,7 +3,7 @@ use gtk::{glib, prelude::*, subclass::prelude::*};
use crate::session::{
room::Room,
- sidebar::{Category, CategoryRow, RoomRow},
+ sidebar::{Category, CategoryRow, Entry, EntryRow, RoomRow},
};
mod imp {
@@ -151,6 +151,21 @@ impl Row {
if let Some(list_item) = self.parent() {
list_item.set_css_classes(&["room"]);
}
+ } else if let Some(entry) = item.downcast_ref::<Entry>() {
+ let child = if let Some(Ok(child)) = self.child().map(|w| w.downcast::<EntryRow>())
+ {
+ child
+ } else {
+ let child = EntryRow::new();
+ self.set_child(Some(&child));
+ child
+ };
+
+ child.set_entry(Some(entry.clone()));
+
+ if let Some(list_item) = self.parent() {
+ list_item.set_css_classes(&["entry"]);
+ }
} else {
panic!("Wrong row item: {:?}", item);
}
diff --git a/src/session/sidebar/selection.rs b/src/session/sidebar/selection.rs
index d74a3f81..544b6bf2 100644
--- a/src/session/sidebar/selection.rs
+++ b/src/session/sidebar/selection.rs
@@ -1,6 +1,6 @@
use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*};
-use crate::session::room::Room;
+use crate::session::{content::ContentType, room::Room, sidebar::Entry};
mod imp {
use super::*;
@@ -11,7 +11,7 @@ mod imp {
pub struct Selection {
pub model: RefCell<Option<gio::ListModel>>,
pub selected: Cell<u32>,
- pub selected_room: RefCell<Option<Room>>,
+ pub selected_item: RefCell<Option<glib::Object>>,
pub signal_handler: RefCell<Option<glib::SignalHandlerId>>,
}
@@ -51,10 +51,18 @@ mod imp {
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
glib::ParamSpec::new_object(
- "selected-room",
- "Selected Room",
- "The selected room",
- Room::static_type(),
+ "selected-item",
+ "Selected Item",
+ "The selected item",
+ glib::Object::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
+ glib::ParamSpec::new_enum(
+ "selected-type",
+ "Selected Type",
+ "The currently selected content type",
+ ContentType::static_type(),
+ ContentType::default() as i32,
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
]
@@ -79,10 +87,8 @@ mod imp {
let selected = value.get().unwrap();
obj.set_selected(selected);
}
- "selected-room" => {
- let selected_room = value.get().unwrap();
- obj.set_selected_room(selected_room);
- }
+ "selected-item" => obj.set_selected_item(value.get().unwrap()),
+ "selected-type" => obj.set_selected_type(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -91,7 +97,8 @@ mod imp {
match pspec.name() {
"model" => obj.model().to_value(),
"selected" => obj.selected().to_value(),
- "selected-room" => obj.selected_room().to_value(),
+ "selected-item" => obj.selected_item().to_value(),
+ "selected-type" => obj.selected_type().to_value(),
_ => unimplemented!(),
}
}
@@ -157,9 +164,77 @@ impl Selection {
priv_.selected.get()
}
- pub fn selected_room(&self) -> Option<Room> {
+ pub fn selected_item(&self) -> Option<glib::Object> {
let priv_ = imp::Selection::from_instance(self);
- priv_.selected_room.borrow().clone()
+ priv_.selected_item.borrow().clone()
+ }
+
+ pub fn selected_type(&self) -> ContentType {
+ if let Some(item) = self.selected_item() {
+ if item.is::<Room>() {
+ return ContentType::Room;
+ } else if let Ok(entry) = item.downcast::<Entry>() {
+ return entry.type_();
+ }
+ }
+
+ ContentType::None
+ }
+
+ pub fn set_selected_type(&self, selected_type: ContentType) {
+ let priv_ = imp::Selection::from_instance(self);
+
+ if self.selected_type() == selected_type {
+ return;
+ }
+
+ match selected_type {
+ ContentType::None => self.set_selected_item(None),
+ ContentType::Room => {
+ if self
+ .selected_item()
+ .and_then(|item| item.downcast::<Room>().ok())
+ .is_none()
+ {
+ if let Some(model) = &*priv_.model.borrow() {
+ for i in 0..model.n_items() {
+ if let Some(room) = model
+ .item(i)
+ .and_then(|item| item.downcast::<gtk::TreeListRow>().ok())
+ .and_then(|i| i.item())
+ .and_then(|o| o.downcast::<Room>().ok())
+ {
+ self.set_selected_item(Some(room.upcast()));
+ break;
+ }
+ }
+ }
+ }
+ }
+ ContentType::Explore => {
+ if !self
+ .selected_item()
+ .and_then(|item| item.downcast::<Entry>().ok())
+ .map_or(false, |entry| entry.type_() == selected_type)
+ {
+ if let Some(model) = &*priv_.model.borrow() {
+ for i in 0..model.n_items() {
+ if let Some(entry) = model
+ .item(i)
+ .and_then(|item| item.downcast::<gtk::TreeListRow>().ok())
+ .and_then(|i| i.item())
+ .and_then(|o| o.downcast::<Entry>().ok())
+ {
+ if entry.type_() == selected_type {
+ self.set_selected_item(Some(entry.upcast()));
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ };
}
pub fn set_model<P: IsA<gio::ListModel>>(&self, model: Option<&P>) {
@@ -202,9 +277,10 @@ impl Selection {
priv_.selected.replace(gtk::INVALID_LIST_POSITION);
self.notify("selected");
}
- if self.selected_room().is_some() {
- priv_.selected_room.replace(None);
- self.notify("selected-room");
+ if self.selected_item().is_some() {
+ priv_.selected_item.replace(None);
+ self.notify("selected-type");
+ self.notify("selected-item");
}
self.items_changed(0, n_items_before, 0);
@@ -221,13 +297,13 @@ impl Selection {
return;
}
- let selected_room = self
+ let selected_item = self
.model()
.and_then(|m| m.item(position))
.and_then(|o| o.downcast::<gtk::TreeListRow>().ok())
- .and_then(|r| r.item())
- .and_then(|o| o.downcast::<Room>().ok());
- let selected = if selected_room.is_none() {
+ .and_then(|r| r.item());
+
+ let selected = if selected_item.is_none() {
gtk::INVALID_LIST_POSITION
} else {
position
@@ -238,7 +314,7 @@ impl Selection {
}
priv_.selected.replace(selected);
- priv_.selected_room.replace(selected_room);
+ priv_.selected_item.replace(selected_item);
if old_selected == gtk::INVALID_LIST_POSITION {
self.selection_changed(selected, 1);
@@ -251,14 +327,15 @@ impl Selection {
}
self.notify("selected");
- self.notify("selected-room");
+ self.notify("selected-item");
+ self.notify("selected-type");
}
- pub fn set_selected_room(&self, room: Option<Room>) {
+ fn set_selected_item(&self, item: Option<glib::Object>) {
let priv_ = imp::Selection::from_instance(self);
- let selected_room = self.selected_room();
- if selected_room == room {
+ let selected_item = self.selected_item();
+ if selected_item == item {
return;
}
@@ -266,15 +343,14 @@ impl Selection {
let mut selected = gtk::INVALID_LIST_POSITION;
- if room.is_some() {
+ if item.is_some() {
if let Some(model) = self.model() {
for i in 0..model.n_items() {
- let r = model
+ let current_item = model
.item(i)
.and_then(|o| o.downcast::<gtk::TreeListRow>().ok())
- .and_then(|r| r.item())
- .and_then(|o| o.downcast::<Room>().ok());
- if r == room {
+ .and_then(|r| r.item());
+ if current_item == item {
selected = i;
break;
}
@@ -282,7 +358,7 @@ impl Selection {
}
}
- priv_.selected_room.replace(room);
+ priv_.selected_item.replace(item);
if old_selected != selected {
priv_.selected.replace(selected);
@@ -299,7 +375,8 @@ impl Selection {
self.notify("selected");
}
- self.notify("selected-room");
+ self.notify("selected-item");
+ self.notify("selected-type");
}
fn items_changed_cb(&self, model: &gio::ListModel, position: u32, removed: u32, added: u32) {
@@ -308,9 +385,9 @@ impl Selection {
let _guard = self.freeze_notify();
let selected = self.selected();
- let selected_room = self.selected_room();
+ let selected_item = self.selected_item();
- if selected_room.is_none() || selected < position {
+ if selected_item.is_none() || selected < position {
// unchanged
} else if selected != gtk::INVALID_LIST_POSITION && selected >= position + removed {
priv_.selected.replace(selected + added - removed);
@@ -322,12 +399,11 @@ impl Selection {
priv_.selected.replace(gtk::INVALID_LIST_POSITION);
self.notify("selected");
} else {
- let room = model
+ let item = model
.item(position + i)
.and_then(|o| o.downcast::<gtk::TreeListRow>().ok())
- .and_then(|r| r.item())
- .and_then(|o| o.downcast::<Room>().ok());
- if room == selected_room {
+ .and_then(|r| r.item());
+ if item == selected_item {
// the item moved
if selected != position + i {
priv_.selected.replace(position + i);
diff --git a/src/session/sidebar/sidebar.rs b/src/session/sidebar/sidebar.rs
index 40d858dd..4b868516 100644
--- a/src/session/sidebar/sidebar.rs
+++ b/src/session/sidebar/sidebar.rs
@@ -2,8 +2,9 @@ use adw::subclass::prelude::BinImpl;
use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
use crate::session::{
+ content::ContentType,
room::Room,
- sidebar::{Category, ItemList, RoomRow, Row, Selection},
+ sidebar::{Category, Entry, ItemList, RoomRow, Row, Selection},
RoomList,
};
@@ -18,6 +19,7 @@ mod imp {
pub struct Sidebar {
pub compact: Cell<bool>,
pub selected_room: RefCell<Option<Room>>,
+ pub selected_type: Cell<ContentType>,
#[template_child]
pub headerbar: TemplateChild<adw::HeaderBar>,
#[template_child]
@@ -68,6 +70,14 @@ mod imp {
Room::static_type(),
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
+ glib::ParamSpec::new_enum(
+ "selected-type",
+ "Selected",
+ "The type of item that is selected",
+ ContentType::static_type(),
+ ContentType::default() as i32,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
]
});
@@ -94,6 +104,7 @@ mod imp {
let selected_room = value.get().unwrap();
obj.set_selected_room(selected_room);
}
+ "selected-type" => obj.set_selected_type(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -102,6 +113,7 @@ mod imp {
match pspec.name() {
"compact" => self.compact.get().to_value(),
"selected-room" => obj.selected_room().to_value(),
+ "selected-type" => obj.selected_type().to_value(),
_ => unimplemented!(),
}
}
@@ -126,6 +138,12 @@ mod imp {
row.set_expanded(!row.is_expanded());
} else if row.item().and_then(|o| o.downcast::<Room>().ok()).is_some() {
model.set_selected(pos);
+ } else if row
+ .item()
+ .and_then(|o| o.downcast::<Entry>().ok())
+ .is_some()
+ {
+ model.set_selected(pos);
}
}
}
@@ -147,6 +165,23 @@ impl Sidebar {
glib::Object::new(&[]).expect("Failed to create Sidebar")
}
+ pub fn selected_type(&self) -> ContentType {
+ let priv_ = imp::Sidebar::from_instance(self);
+ priv_.selected_type.get()
+ }
+
+ fn set_selected_type(&self, selected_type: ContentType) {
+ let priv_ = imp::Sidebar::from_instance(self);
+
+ if self.selected_type() == selected_type {
+ return;
+ }
+
+ priv_.selected_type.set(selected_type);
+
+ self.notify("selected-type");
+ }
+
pub fn selected_room(&self) -> Option<Room> {
let priv_ = imp::Sidebar::from_instance(self);
priv_.selected_room.borrow().clone()
@@ -188,7 +223,11 @@ impl Sidebar {
.build();
let selection = Selection::new(Some(&filter_model));
- self.bind_property("selected-room", &selection, "selected-room")
+ self.bind_property("selected-room", &selection, "selected-item")
+ .flags(glib::BindingFlags::SYNC_CREATE | glib::BindingFlags::BIDIRECTIONAL)
+ .build();
+
+ self.bind_property("selected-type", &selection, "selected-type")
.flags(glib::BindingFlags::SYNC_CREATE | glib::BindingFlags::BIDIRECTIONAL)
.build();
@@ -206,7 +245,6 @@ impl Sidebar {
}
priv_.selected_room.replace(selected_room);
-
self.notify("selected-room");
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]