Browse Source

sidebar: Improve items look

merge-requests/1327/merge
Kévin Commaille 5 years ago committed by Julian Sparber
parent
commit
29a98b2e2b
  1. 1
      data/resources/resources.gresource.xml
  2. 34
      data/resources/style.css
  3. 32
      data/resources/ui/sidebar-category-row.ui
  4. 11
      data/resources/ui/sidebar-item.ui
  5. 2
      data/resources/ui/sidebar-room-row.ui
  6. 158
      src/session/sidebar/category_row.rs
  7. 2
      src/session/sidebar/mod.rs
  8. 74
      src/session/sidebar/row.rs
  9. 23
      src/session/sidebar/sidebar.rs

1
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>

34
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;
}

32
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>

11
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>

2
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>

158
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");
}
}

2
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;

74
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");
}
}

23
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 {}

Loading…
Cancel
Save