Move time code from old-panel into an applet

Removes the last of `old-panel`.
This commit is contained in:
Ian Douglas Scott 2022-06-10 16:20:46 -07:00
parent fb321a2e05
commit 9b58739a96
16 changed files with 191 additions and 541 deletions

View file

@ -0,0 +1,31 @@
use once_cell::unsync::OnceCell;
/// Wrapper around `OnceCell` implementing `Deref`, and thus also panicking
/// when not set (or set twice).
///
/// To be used in place of `gtk::TemplateChild`, but without xml.
pub struct DerefCell<T>(OnceCell<T>);
impl<T> DerefCell<T> {
#[track_caller]
pub fn set(&self, value: T) {
if self.0.set(value).is_err() {
panic!("Initialized twice");
}
}
}
impl<T> Default for DerefCell<T> {
fn default() -> Self {
Self(OnceCell::default())
}
}
impl<T> std::ops::Deref for DerefCell<T> {
type Target = T;
#[track_caller]
fn deref(&self) -> &T {
self.0.get().unwrap()
}
}

View file

@ -0,0 +1,32 @@
use gtk4::{glib, prelude::*};
mod deref_cell;
mod time_button;
use time_button::TimeButton;
fn main() {
gtk4::init().unwrap();
let provider = gtk4::CssProvider::new();
provider.load_from_data(include_bytes!("style.css"));
gtk4::StyleContext::add_provider_for_display(
&gtk4::gdk::Display::default().expect("Could not connect to a display."),
&provider,
gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
let time_button = TimeButton::new();
gtk4::Window::builder()
.decorated(false)
.child(&time_button)
.resizable(false)
.width_request(1)
.height_request(1)
.css_classes(vec!["root_window".to_string()])
.build()
.show();
let main_loop = glib::MainLoop::new(None, false);
main_loop.run();
}

View file

@ -0,0 +1,33 @@
.loading-overlay {
background-color: #2f2f2f;
opacity: 0.85;
}
image.panel_icon {
padding-left: 0px;
padding-right: 0px;
padding-top: 0px;
padding-bottom: 0px;
}
button.panel_icon {
border-radius: 12px;
transition: 100ms;
padding: 4px;
border-color: transparent;
background: transparent;
outline-color: transparent;
}
button.panel_icon:hover {
border-radius: 12px;
transition: 100ms;
padding: 4px;
border-color: rgba(255, 255, 255, 0.1);
outline-color: rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.1);
}
window.root_window {
background: transparent;
}

View file

@ -0,0 +1,110 @@
use cascade::cascade;
use gtk4::{
glib::{self, clone},
pango,
prelude::*,
subclass::prelude::*,
};
use crate::deref_cell::DerefCell;
#[derive(Default)]
pub struct TimeButtonInner {
calendar: DerefCell<gtk4::Calendar>,
button: DerefCell<gtk4::MenuButton>,
label: DerefCell<gtk4::Label>,
}
#[glib::object_subclass]
impl ObjectSubclass for TimeButtonInner {
const NAME: &'static str = "S76TimeButton";
type ParentType = gtk4::Widget;
type Type = TimeButton;
fn class_init(klass: &mut Self::Class) {
klass.set_layout_manager_type::<gtk4::BinLayout>();
}
}
impl ObjectImpl for TimeButtonInner {
fn constructed(&self, obj: &TimeButton) {
let calendar = cascade! {
gtk4::Calendar::new();
};
let label = cascade! {
gtk4::Label::new(None);
..set_attributes(Some(&cascade! {
pango::AttrList::new();
..insert(pango::AttrInt::new_weight(pango::Weight::Bold));
}));
};
let popover = cascade! {
gtk4::Popover::new();
..set_child(Some(&cascade! {
gtk4::Box::new(gtk4::Orientation::Horizontal, 0);
..append(&calendar);
}));
..connect_show(clone!(@strong obj => move |_| obj.opening()));
};
let button = cascade! {
gtk4::MenuButton::new();
..set_child(Some(&label));
..set_has_frame(false);
..set_parent(obj);
..set_popover(Some(&popover));
};
self.calendar.set(calendar);
self.button.set(button);
self.label.set(label);
// TODO: better way to do this?
glib::timeout_add_seconds_local(
1,
clone!(@weak obj => @default-return glib::Continue(false), move || {
obj.update_time();
glib::Continue(true)
}),
);
obj.update_time();
}
fn dispose(&self, _obj: &TimeButton) {
self.button.unparent();
}
}
impl WidgetImpl for TimeButtonInner {}
glib::wrapper! {
pub struct TimeButton(ObjectSubclass<TimeButtonInner>)
@extends gtk4::Widget;
}
impl TimeButton {
pub fn new() -> Self {
glib::Object::new::<Self>(&[]).unwrap()
}
fn inner(&self) -> &TimeButtonInner {
TimeButtonInner::from_instance(self)
}
fn opening(&self) {
let date = glib::DateTime::now(&glib::TimeZone::local()).unwrap();
self.inner().calendar.clear_marks();
self.inner().calendar.select_day(&date);
}
fn update_time(&self) {
// TODO: Locale-based formatting?
let time = chrono::Local::now();
self.inner()
.label
.set_label(&time.format("%b %-d %-I:%M %p").to_string());
// time.format("%B %-d %Y")
}
}