[fractal/fractal-next] sidebar: Improve items look
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] sidebar: Improve items look
- Date: Wed, 5 May 2021 09:29:50 +0000 (UTC)
commit 29a98b2e2bddafc5bece081dc986997e9e4092ee
Author: Kévin Commaille <zecakeh tedomum fr>
Date: Tue May 4 21:01:32 2021 +0200
sidebar: Improve items look
data/resources/resources.gresource.xml | 1 +
data/resources/style.css | 34 +++++--
data/resources/ui/sidebar-category-row.ui | 32 ++++++
data/resources/ui/sidebar-item.ui | 11 +--
data/resources/ui/sidebar-room-row.ui | 2 +-
src/session/sidebar/category_row.rs | 158 ++++++++++++++++++++++++++++++
src/session/sidebar/mod.rs | 2 +
src/session/sidebar/row.rs | 74 +++++++++-----
src/session/sidebar/sidebar.rs | 23 ++++-
9 files changed, 295 insertions(+), 42 deletions(-)
---
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index 499c665b..037753ad 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -11,6 +11,7 @@
<file compressed="true" preprocess="xml-stripblanks" alias="session.ui">ui/session.ui</file>
<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-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>
diff --git a/data/resources/style.css b/data/resources/style.css
index a3218d67..335ee9e0 100644
--- a/data/resources/style.css
+++ b/data/resources/style.css
@@ -21,21 +21,39 @@
}
/* Sidebar */
-.sidebar row .dim-label {
- padding: 6px 12px;
+.sidebar row {
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+.sidebar .category {
+ margin-top: 4px;
font-size: 0.8em;
font-weight: bold;
}
-.sidebar row .bold {
- font-weight: bold;
+.sidebar .category image.arrow {
+ transition: 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
+}
+
+.sidebar .category .category-row:not(:checked) image.arrow:dir(ltr) {
+ transform: rotate(-0.25turn);
}
-.sidebar indent {
- -gtk-icon-size: 0px;
+.sidebar .category .category-row:not(:checked) image.arrow:dir(rtl) {
+ transform: rotate(0.25turn);
+}
+
+.sidebar .room {
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+
+.sidebar .room .bold {
+ font-weight: bold;
}
-.sidebar row .notification_count {
+.sidebar .room .notification_count {
/* TODO: use correct color variable */
background-color: #555;
color: white;
@@ -46,7 +64,7 @@
padding: 2px 5px;
}
-.sidebar row .highlight {
+.sidebar .room .highlight {
/* TODO: use correct color variable */
background-color: @theme_selected_bg_color;
}
diff --git a/data/resources/ui/sidebar-category-row.ui b/data/resources/ui/sidebar-category-row.ui
new file mode 100644
index 00000000..ef3607bd
--- /dev/null
+++ b/data/resources/ui/sidebar-category-row.ui
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="SidebarCategoryRow" parent="AdwBin">
+ <style>
+ <class name="category-row"/>
+ </style>
+ <child>
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkLabel" id="display_name">
+ <property name="halign">start</property>
+ <property name="hexpand">True</property>
+ <property name="ellipsize">end</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkImage" id="arrow">
+ <property name="icon-name">adw-expander-arrow-symbolic</property>
+ <style>
+ <class name="arrow"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+
diff --git a/data/resources/ui/sidebar-item.ui b/data/resources/ui/sidebar-item.ui
index 8697f3d0..8bbc4c63 100644
--- a/data/resources/ui/sidebar-item.ui
+++ b/data/resources/ui/sidebar-item.ui
@@ -2,19 +2,10 @@
<interface>
<template class="GtkListItem">
<property name="child">
- <!-- TODO: we need to implement our own Expander:
https://gitlab.gnome.org/GNOME/fractal/-/issues/749-->
- <object class="GtkTreeExpander" id="expander">
+ <object class="SidebarRow">
<binding name="list-row">
<lookup name="item">GtkListItem</lookup>
</binding>
- <property name="child">
- <object class="SidebarRow">
- <property name="hexpand">True</property>
- <binding name="item">
- <lookup name="item">expander</lookup>
- </binding>
- </object>
- </property>
</object>
</property>
</template>
diff --git a/data/resources/ui/sidebar-room-row.ui b/data/resources/ui/sidebar-room-row.ui
index 7adad266..d5060291 100644
--- a/data/resources/ui/sidebar-room-row.ui
+++ b/data/resources/ui/sidebar-room-row.ui
@@ -3,7 +3,7 @@
<template class="SidebarRoomRow" parent="AdwBin">
<child>
<object class="GtkBox">
- <property name="spacing">6</property>
+ <property name="spacing">12</property>
<child>
<object class="AdwAvatar" id="avatar">
<property name="show-initials">True</property>
diff --git a/src/session/sidebar/category_row.rs b/src/session/sidebar/category_row.rs
new file mode 100644
index 00000000..4706776e
--- /dev/null
+++ b/src/session/sidebar/category_row.rs
@@ -0,0 +1,158 @@
+use adw;
+use adw::subclass::prelude::BinImpl;
+use gtk::subclass::prelude::*;
+use gtk::{self, prelude::*};
+use gtk::{glib, CompositeTemplate};
+
+use crate::session::categories::Category;
+
+mod imp {
+ use super::*;
+ use glib::subclass::InitializingObject;
+ use std::cell::{Cell, RefCell};
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/FractalNext/sidebar-category-row.ui")]
+ pub struct CategoryRow {
+ pub category: RefCell<Option<Category>>,
+ pub expanded: Cell<bool>,
+ pub binding: RefCell<Option<glib::Binding>>,
+ #[template_child]
+ pub display_name: TemplateChild<gtk::Label>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for CategoryRow {
+ const NAME: &'static str = "SidebarCategoryRow";
+ type Type = super::CategoryRow;
+ 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 CategoryRow {
+ fn properties() -> &'static [glib::ParamSpec] {
+ use once_cell::sync::Lazy;
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpec::new_object(
+ "category",
+ "Category",
+ "The category of this row",
+ Category::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
+ glib::ParamSpec::new_boolean(
+ "expanded",
+ "Expanded",
+ "The expanded state of this row",
+ true,
+ 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() {
+ "category" => {
+ let category = value.get().unwrap();
+ obj.set_category(category);
+ }
+ "expanded" => {
+ let expanded = value.get().unwrap();
+ obj.set_expanded(expanded);
+ }
+ _ => unimplemented!(),
+ }
+ }
+
+ fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "category" => obj.category().to_value(),
+ "expanded" => obj.expanded().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+ }
+
+ impl WidgetImpl for CategoryRow {}
+ impl BinImpl for CategoryRow {}
+}
+
+glib::wrapper! {
+ pub struct CategoryRow(ObjectSubclass<imp::CategoryRow>)
+ @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
+}
+
+impl CategoryRow {
+ pub fn new() -> Self {
+ glib::Object::new(&[]).expect("Failed to create CategoryRow")
+ }
+
+ pub fn category(&self) -> Option<Category> {
+ let priv_ = imp::CategoryRow::from_instance(&self);
+ priv_.category.borrow().clone()
+ }
+
+ pub fn set_category(&self, category: Option<Category>) {
+ let priv_ = imp::CategoryRow::from_instance(&self);
+
+ if self.category() == category {
+ return;
+ }
+
+ if let Some(binding) = priv_.binding.take() {
+ binding.unbind();
+ }
+
+ if let Some(ref category) = category {
+ let binding = category
+ .bind_property("display-name", &priv_.display_name.get(), "label")
+ .flags(glib::BindingFlags::SYNC_CREATE)
+ .build()
+ .unwrap();
+
+ priv_.binding.replace(Some(binding));
+ }
+
+ priv_.category.replace(category);
+ self.notify("category");
+ }
+
+ fn expanded(&self) -> bool {
+ let priv_ = imp::CategoryRow::from_instance(&self);
+ priv_.expanded.get()
+ }
+
+ fn set_expanded(&self, expanded: bool) {
+ let priv_ = imp::CategoryRow::from_instance(&self);
+
+ if self.expanded() == expanded {
+ return;
+ }
+
+ if expanded {
+ self.set_state_flags(gtk::StateFlags::CHECKED, false);
+ } else {
+ self.unset_state_flags(gtk::StateFlags::CHECKED);
+ }
+
+ priv_.expanded.set(expanded);
+ self.notify("expanded");
+ }
+}
diff --git a/src/session/sidebar/mod.rs b/src/session/sidebar/mod.rs
index 17e19937..34b3697a 100644
--- a/src/session/sidebar/mod.rs
+++ b/src/session/sidebar/mod.rs
@@ -1,7 +1,9 @@
+mod category_row;
mod room_row;
mod row;
mod sidebar;
+use self::category_row::CategoryRow;
use self::room_row::RoomRow;
use self::row::Row;
pub use self::sidebar::Sidebar;
diff --git a/src/session/sidebar/row.rs b/src/session/sidebar/row.rs
index d0845c4c..6cf0c7e2 100644
--- a/src/session/sidebar/row.rs
+++ b/src/session/sidebar/row.rs
@@ -1,7 +1,7 @@
use adw::{subclass::prelude::BinImpl, BinExt};
use gtk::{glib, prelude::*, subclass::prelude::*};
-use crate::session::sidebar::RoomRow;
+use crate::session::sidebar::{CategoryRow, RoomRow};
use crate::session::{categories::Category, room::Room};
mod imp {
@@ -11,7 +11,7 @@ mod imp {
#[derive(Debug, Default)]
pub struct Row {
- pub item: RefCell<Option<glib::Object>>,
+ pub list_row: RefCell<Option<gtk::TreeListRow>>,
pub binding: RefCell<Option<glib::Binding>>,
}
@@ -25,13 +25,22 @@ mod imp {
impl ObjectImpl for Row {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
- vec![glib::ParamSpec::new_object(
- "item",
- "Item",
- "The sidebar item of this row",
- glib::Object::static_type(),
- glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
- )]
+ vec![
+ glib::ParamSpec::new_object(
+ "item",
+ "Item",
+ "The sidebar item of this row",
+ glib::Object::static_type(),
+ glib::ParamFlags::READABLE,
+ ),
+ glib::ParamSpec::new_object(
+ "list-row",
+ "List Row",
+ "The list row to track for expander state",
+ gtk::TreeListRow::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
+ ]
});
PROPERTIES.as_ref()
@@ -45,9 +54,9 @@ mod imp {
pspec: &glib::ParamSpec,
) {
match pspec.name() {
- "item" => {
- let item = value.get().unwrap();
- obj.set_item(item);
+ "list-row" => {
+ let list_row = value.get().unwrap();
+ obj.set_list_row(list_row);
}
_ => unimplemented!(),
}
@@ -56,6 +65,7 @@ mod imp {
fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"item" => obj.item().to_value(),
+ "list-row" => obj.list_row().to_value(),
_ => unimplemented!(),
}
}
@@ -76,14 +86,18 @@ impl Row {
}
pub fn item(&self) -> Option<glib::Object> {
+ self.list_row().and_then(|r| r.item())
+ }
+
+ pub fn list_row(&self) -> Option<gtk::TreeListRow> {
let priv_ = imp::Row::from_instance(&self);
- priv_.item.borrow().clone()
+ priv_.list_row.borrow().clone()
}
- pub fn set_item(&self, item: Option<glib::Object>) {
+ pub fn set_list_row(&self, list_row: Option<gtk::TreeListRow>) {
let priv_ = imp::Row::from_instance(&self);
- if self.item() == item {
+ if self.list_row() == list_row {
return;
}
@@ -91,26 +105,36 @@ impl Row {
binding.unbind();
}
- if let Some(item) = item {
+ let row = if let Some(row) = list_row.clone() {
+ priv_.list_row.replace(list_row.clone());
+ row
+ } else {
+ return;
+ };
+
+ if let Some(item) = self.item() {
if let Some(category) = item.downcast_ref::<Category>() {
let child =
- if let Some(Ok(child)) = self.child().map(|w| w.downcast::<gtk::Label>()) {
+ if let Some(Ok(child)) = self.child().map(|w| w.downcast::<CategoryRow>()) {
child
} else {
- let child = gtk::Label::new(None);
+ let child = CategoryRow::new();
self.set_child(Some(&child));
- self.set_halign(gtk::Align::Start);
- child.add_css_class("dim-label");
child
};
+ child.set_category(Some(category.clone()));
- let binding = category
- .bind_property("display-name", &child, "label")
+ let binding = row
+ .bind_property("expanded", &child, "expanded")
.flags(glib::BindingFlags::SYNC_CREATE)
.build()
.unwrap();
priv_.binding.replace(Some(binding));
+
+ if let Some(list_item) = self.parent() {
+ list_item.set_css_classes(&["category"]);
+ }
} else if let Some(room) = item.downcast_ref::<Room>() {
let child = if let Some(Ok(child)) = self.child().map(|w| w.downcast::<RoomRow>()) {
child
@@ -121,10 +145,16 @@ impl Row {
};
child.set_room(Some(room.clone()));
+
+ if let Some(list_item) = self.parent() {
+ list_item.set_css_classes(&["room"]);
+ }
} else {
panic!("Wrong row item: {:?}", item);
}
}
+
self.notify("item");
+ self.notify("list-row");
}
}
diff --git a/src/session/sidebar/sidebar.rs b/src/session/sidebar/sidebar.rs
index 020ebd65..07caf238 100644
--- a/src/session/sidebar/sidebar.rs
+++ b/src/session/sidebar/sidebar.rs
@@ -2,7 +2,7 @@ use adw::subclass::prelude::BinImpl;
use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*, CompositeTemplate};
use crate::session::{
- categories::Categories,
+ categories::{Categories, Category},
room::Room,
sidebar::{RoomRow, Row},
};
@@ -105,6 +105,27 @@ mod imp {
_ => unimplemented!(),
}
}
+
+ fn constructed(&self, obj: &Self::Type) {
+ self.parent_constructed(obj);
+
+ self.listview.get().connect_activate(move |listview, pos| {
+ if let Some(row) = listview
+ .model()
+ .and_then(|m| m.downcast::<gtk::SingleSelection>().ok())
+ .and_then(|m| m.item(pos))
+ .and_then(|o| o.downcast::<gtk::TreeListRow>().ok())
+ {
+ if row
+ .item()
+ .and_then(|o| o.downcast::<Category>().ok())
+ .is_some()
+ {
+ row.set_expanded(!row.is_expanded());
+ }
+ }
+ });
+ }
}
impl WidgetImpl for Sidebar {}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]