Browse Source

components: Add RoomTitle component

Adds a custom RoomTitle widget in place of AdwWindowTitle.
This will allow us to have markup in titles and subtitles,
and allow us to have tooltips set appropriately.
merge-requests/1327/merge
Christopher Davis 5 years ago
parent
commit
5d95eb56bb
  1. 1
      data/resources/resources.gresource.xml
  2. 2
      data/resources/ui/content-room-history.ui
  3. 42
      data/resources/ui/room-title.ui
  4. 2
      src/components/mod.rs
  5. 140
      src/components/room_title.rs
  6. 1
      src/meson.build
  7. 3
      src/session/content/room_history.rs

1
data/resources/resources.gresource.xml

@ -25,6 +25,7 @@
<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>
<file compressed="true" preprocess="xml-stripblanks" alias="pill.ui">ui/pill.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="room-title.ui">ui/room-title.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="spinner-button.ui">ui/spinner-button.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="in-app-notification.ui">ui/in-app-notification.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="components-avatar.ui">ui/components-avatar.ui</file>

2
data/resources/ui/content-room-history.ui

@ -31,7 +31,7 @@
</object>
</child>
<child type="title">
<object class="AdwWindowTitle">
<object class="RoomTitle" id="room_title">
<binding name="title">
<lookup name="display-name">
<lookup name="room">ContentRoomHistory</lookup>

42
data/resources/ui/room-title.ui

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="RoomTitle" parent="AdwBin">
<child>
<object class="GtkBox" id="box">
<property name="orientation">vertical</property>
<property name="halign">center</property>
<property name="valign">center</property>
<child>
<object class="GtkLabel" id="title_label">
<property name="ellipsize">end</property>
<property name="halign">center</property>
<property name="wrap">False</property>
<property name="single-line-mode">True</property>
<property name="use-markup">True</property>
<property name="width-chars">5</property>
<property name="label" bind-source="RoomTitle" bind-property="title" bind-flags="sync-create"/>
<property name="tooltip-markup" bind-source="RoomTitle" bind-property="title" bind-flags="sync-create"/>
<style>
<class name="title"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="subtitle_label">
<property name="ellipsize">end</property>
<property name="halign">center</property>
<property name="wrap">False</property>
<property name="single-line-mode">True</property>
<property name="use-markup">True</property>
<property name="visible">False</property>
<property name="label" bind-source="RoomTitle" bind-property="subtitle" bind-flags="sync-create"/>
<property name="tooltip-markup" bind-source="RoomTitle" bind-property="subtitle" bind-flags="sync-create"/>
<style>
<class name="subtitle"/>
</style>
</object>
</child>
</object>
</child>
</template>
</interface>

2
src/components/mod.rs

@ -3,6 +3,7 @@ mod context_menu_bin;
mod in_app_notification;
mod label_with_widgets;
mod pill;
mod room_title;
mod spinner_button;
pub use self::avatar::Avatar;
@ -10,4 +11,5 @@ pub use self::context_menu_bin::{ContextMenuBin, ContextMenuBinExt, ContextMenuB
pub use self::in_app_notification::InAppNotification;
pub use self::label_with_widgets::LabelWithWidgets;
pub use self::pill::Pill;
pub use self::room_title::RoomTitle;
pub use self::spinner_button::SpinnerButton;

140
src/components/room_title.rs

@ -0,0 +1,140 @@
use adw::subclass::prelude::*;
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use gtk::{glib, CompositeTemplate};
mod imp {
use super::*;
use glib::subclass::InitializingObject;
use std::cell::RefCell;
#[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/org/gnome/FractalNext/room-title.ui")]
pub struct RoomTitle {
// The markup for the title
pub title: RefCell<Option<String>>,
// The markup for the subtitle
pub subtitle: RefCell<Option<String>>,
#[template_child]
pub title_label: TemplateChild<gtk::Label>,
#[template_child]
pub subtitle_label: TemplateChild<gtk::Label>,
}
#[glib::object_subclass]
impl ObjectSubclass for RoomTitle {
const NAME: &'static str = "RoomTitle";
type Type = super::RoomTitle;
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 RoomTitle {
fn properties() -> &'static [glib::ParamSpec] {
use once_cell::sync::Lazy;
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![
glib::ParamSpec::new_string(
"title",
"Title",
"The title of the room",
None,
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
glib::ParamSpec::new_string(
"subtitle",
"Subtitle",
"The subtitle of the room",
None,
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
]
});
PROPERTIES.as_ref()
}
fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"title" => obj.title().to_value(),
"subtitle" => obj.subtitle().to_value(),
_ => unimplemented!(),
}
}
fn set_property(
&self,
obj: &Self::Type,
_id: usize,
value: &glib::Value,
pspec: &glib::ParamSpec,
) {
match pspec.name() {
"title" => obj.set_title(value.get().unwrap()),
"subtitle" => obj.set_subtitle(value.get().unwrap()),
_ => unimplemented!(),
}
}
fn constructed(&self, obj: &Self::Type) {
self.parent_constructed(obj);
}
}
impl WidgetImpl for RoomTitle {}
impl BinImpl for RoomTitle {}
}
glib::wrapper! {
pub struct RoomTitle(ObjectSubclass<imp::RoomTitle>)
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
}
impl RoomTitle {
pub fn new() -> Self {
glib::Object::new(&[]).expect("Failed to create RoomTitle")
}
pub fn set_title(&self, title: Option<String>) {
let priv_ = imp::RoomTitle::from_instance(self);
// If there's an existing title, check that current title and new title aren't equal
if priv_.title.borrow().as_deref() != title.as_deref() {
priv_.title.replace(title);
priv_
.title_label
.set_visible(priv_.title.borrow().is_some());
}
self.notify("title");
}
pub fn title(&self) -> Option<String> {
let priv_ = imp::RoomTitle::from_instance(self);
priv_.title.borrow().clone()
}
pub fn set_subtitle(&self, subtitle: Option<String>) {
let priv_ = imp::RoomTitle::from_instance(self);
// If there's an existing subtitle, check that current subtitle and new subtitle aren't equal
if priv_.subtitle.borrow().as_deref() != subtitle.as_deref() {
priv_.subtitle.replace(subtitle);
priv_
.subtitle_label
.set_visible(priv_.subtitle.borrow().is_some());
}
self.notify("subtitle");
}
pub fn subtitle(&self) -> Option<String> {
let priv_ = imp::RoomTitle::from_instance(self);
priv_.subtitle.borrow().clone()
}
}

1
src/meson.build

@ -25,6 +25,7 @@ sources = files(
'components/label_with_widgets.rs',
'components/mod.rs',
'components/pill.rs',
'components/room_title.rs',
'components/in_app_notification.rs',
'components/spinner_button.rs',
'config.rs',

3
src/session/content/room_history.rs

@ -1,3 +1,4 @@
use crate::components::RoomTitle;
use crate::session::{content::ItemRow, content::MarkdownPopover, room::Room, room::RoomType};
use adw::subclass::prelude::*;
use gtk::{
@ -22,6 +23,8 @@ mod imp {
#[template_child]
pub headerbar: TemplateChild<adw::HeaderBar>,
#[template_child]
pub room_title: TemplateChild<RoomTitle>,
#[template_child]
pub room_menu: TemplateChild<gtk::MenuButton>,
#[template_child]
pub listview: TemplateChild<gtk::ListView>,

Loading…
Cancel
Save