181 lines
6.2 KiB
Rust
181 lines
6.2 KiB
Rust
use gio::prelude::SettingsExt;
|
|
use gtk::{prelude::*, subclass::prelude::*};
|
|
use libhandy::prelude::HdyHeaderBarExt;
|
|
|
|
glib::wrapper! {
|
|
pub struct MainWindow(ObjectSubclass<imp::MainWindow>)
|
|
@extends libhandy::ApplicationWindow, gtk::ApplicationWindow, gtk::Window, gtk::Bin, gtk::Container, gtk::Widget, gio::ActionMap;
|
|
}
|
|
|
|
impl MainWindow {
|
|
pub(crate) fn new() -> Self {
|
|
glib::Object::new(&[]).expect("Failed to create main window")
|
|
}
|
|
|
|
pub(crate) fn to_obs(&self) {
|
|
let this = imp::MainWindow::from_instance(self);
|
|
let inner = this.inner.get().unwrap();
|
|
let borrowed = inner.borrow();
|
|
if let Some(stack) = borrowed.main_stack.as_ref() {
|
|
stack.set_visible_child_name("obs-config");
|
|
}
|
|
}
|
|
|
|
pub(crate) fn build_ui(&self) {
|
|
self.set_height_request(350);
|
|
self.set_width_request(400);
|
|
self.set_title("Streamdeck");
|
|
|
|
if let Some(variant) = crate::saved_state().user_value("window-size") {
|
|
if let Some((width, height)) = variant.get::<(i32, i32)>() {
|
|
self.set_default_size(width, height);
|
|
}
|
|
}
|
|
if let Some(variant) = crate::saved_state().user_value("window-position") {
|
|
if let Some((x, y)) = variant.get::<(i32, i32)>() {
|
|
if x != -1 || y != -1 {
|
|
self.move_(x, y)
|
|
}
|
|
}
|
|
}
|
|
|
|
if crate::saved_state().boolean("window-maximized") {
|
|
self.maximize();
|
|
}
|
|
|
|
let main_stack = gtk::Stack::new();
|
|
main_stack.add_titled(&crate::views::DeckView::new(), "deck-config", "Streamdecks");
|
|
main_stack.add_titled(&crate::views::Obs::new(), "obs-config", "OBS");
|
|
|
|
let stack_switcher = gtk::StackSwitcher::new();
|
|
stack_switcher.set_margin(12);
|
|
stack_switcher.set_halign(gtk::Align::Center);
|
|
stack_switcher.set_homogeneous(true);
|
|
stack_switcher.set_stack(Some(&main_stack));
|
|
|
|
let headerbar = libhandy::HeaderBar::new();
|
|
headerbar.set_show_close_button(true);
|
|
headerbar.set_title(Some("Streamdeck"));
|
|
headerbar.show_all();
|
|
|
|
let grid = gtk::Grid::new();
|
|
grid.attach(&headerbar, 0, 0, 1, 1);
|
|
grid.attach(&stack_switcher, 0, 1, 1, 1);
|
|
grid.attach(&main_stack, 0, 2, 1, 1);
|
|
grid.show_all();
|
|
|
|
self.add(&grid);
|
|
|
|
self.show_all();
|
|
|
|
let this = imp::MainWindow::from_instance(self);
|
|
let inner = this.inner.get().unwrap();
|
|
inner.borrow_mut().main_stack = Some(main_stack);
|
|
}
|
|
}
|
|
|
|
mod imp {
|
|
use gio::prelude::SettingsExt;
|
|
use gtk::{prelude::*, subclass::prelude::*};
|
|
use once_cell::unsync::OnceCell;
|
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
|
|
|
#[derive(Default, Debug)]
|
|
pub(super) struct WindowInner {
|
|
pub(super) actions: HashMap<String, gio::Action>,
|
|
pub(super) main_stack: Option<gtk::Stack>,
|
|
pub(super) configure_id: Option<glib::source::SourceId>,
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct MainWindow {
|
|
pub(super) inner: OnceCell<Rc<RefCell<WindowInner>>>,
|
|
}
|
|
|
|
#[glib::object_subclass]
|
|
impl ObjectSubclass for MainWindow {
|
|
const NAME: &'static str = "MainWindow";
|
|
type Type = super::MainWindow;
|
|
type ParentType = libhandy::ApplicationWindow;
|
|
}
|
|
|
|
impl ObjectImpl for MainWindow {
|
|
fn constructed(&self, obj: &Self::Type) {
|
|
self.parent_constructed(obj);
|
|
|
|
self.inner
|
|
.set(Rc::new(RefCell::new(WindowInner {
|
|
actions: HashMap::new(),
|
|
main_stack: None,
|
|
configure_id: None,
|
|
})))
|
|
.unwrap();
|
|
}
|
|
}
|
|
|
|
impl ActionMapImpl for MainWindow {
|
|
fn lookup_action(&self, _: &Self::Type, name: &str) -> Option<gio::Action> {
|
|
let inner = self.inner.get().unwrap();
|
|
inner
|
|
.borrow()
|
|
.actions
|
|
.get(name)
|
|
.map(|action| action.clone())
|
|
}
|
|
|
|
fn add_action(&self, _: &Self::Type, action: &gio::Action) {
|
|
let inner = self.inner.get().unwrap();
|
|
inner
|
|
.borrow_mut()
|
|
.actions
|
|
.insert(action.name().into(), action.clone());
|
|
}
|
|
|
|
fn remove_action(&self, _: &Self::Type, name: &str) {
|
|
let inner = self.inner.get().unwrap();
|
|
inner.borrow_mut().actions.remove(name);
|
|
}
|
|
}
|
|
|
|
impl WidgetImpl for MainWindow {
|
|
fn configure_event(&self, obj: &Self::Type, event: &gdk::EventConfigure) -> gtk::Inhibit {
|
|
let inner = self.inner.get().unwrap();
|
|
|
|
if inner.borrow().configure_id.is_none() {
|
|
let new_configure_id = glib::source::timeout_add_local(
|
|
std::time::Duration::from_millis(200),
|
|
glib::clone!(@weak-allow-none obj => move || {
|
|
if let Some(obj) = obj {
|
|
let this = MainWindow::from_instance(&obj);
|
|
let inner = this.inner.get().unwrap();
|
|
inner.borrow_mut().configure_id = None;
|
|
|
|
let saved_state = crate::saved_state();
|
|
|
|
let _ = saved_state.set_boolean("window-maximized", obj.is_maximized());
|
|
|
|
if !obj.is_maximized() {
|
|
let _ = saved_state
|
|
.set_value("window-position", &obj.position().to_variant());
|
|
let _ =
|
|
saved_state.set_value("window-size", &obj.size().to_variant());
|
|
}
|
|
}
|
|
|
|
glib::source::Continue(false)
|
|
}),
|
|
);
|
|
|
|
inner.borrow_mut().configure_id = Some(new_configure_id);
|
|
}
|
|
|
|
self.parent_configure_event(obj, event)
|
|
}
|
|
}
|
|
impl ContainerImpl for MainWindow {}
|
|
impl BinImpl for MainWindow {}
|
|
impl WindowImpl for MainWindow {}
|
|
impl ApplicationWindowImpl for MainWindow {}
|
|
impl libhandy::subclass::prelude::HdyApplicationWindowImpl for MainWindow {}
|
|
}
|