mirror of
https://github.com/Xetibo/ReSet.git
synced 2025-04-19 11:08:32 +02:00
454 lines
15 KiB
Rust
454 lines
15 KiB
Rust
use std::cell::RefCell;
|
|
use std::rc::Rc;
|
|
use std::sync::Arc;
|
|
|
|
use adw::glib::clone;
|
|
use adw::subclass::prelude::ObjectSubclassIsExt;
|
|
use adw::BreakpointCondition;
|
|
use glib::Object;
|
|
use gtk::gio::ActionEntry;
|
|
use gtk::{
|
|
gio, AccessibleRole, Align, Application, FlowBox, FlowBoxChild, Frame, ListBoxRow, Orientation,
|
|
StateFlags,
|
|
};
|
|
use gtk::{prelude::*, DirectionType};
|
|
use re_set_lib::utils::plugin_setup::FRONTEND_PLUGINS;
|
|
|
|
use crate::components::base::setting_box::SettingBox;
|
|
use crate::components::base::utils::{Listeners, Position};
|
|
use crate::components::plugin::function::PluginSidebarInfo;
|
|
use crate::components::utils::get_capabilities;
|
|
use crate::components::window::handle_sidebar_click::*;
|
|
use crate::components::window::reset_window_impl;
|
|
use crate::components::window::sidebar_entry::SidebarEntry;
|
|
use crate::VERSION;
|
|
|
|
use super::consts::{
|
|
AUDIO_SIDEBAR, BLUETOOTH_SIDEBAR, CONNECTIVITY_SIDEBAR, SINK_SIDEBAR, SOURCE_SIDEBAR,
|
|
WIFI_SIDEBAR,
|
|
};
|
|
|
|
glib::wrapper! {
|
|
pub struct ReSetWindow(ObjectSubclass<reset_window_impl::ReSetWindow>)
|
|
@extends adw::ApplicationWindow, gtk::Window, gtk::Widget,
|
|
@implements gio::ActionGroup, gio::ActionMap, gtk::Accessible, gtk::Buildable,
|
|
gtk::ConstraintTarget, gtk::Native, gtk::Root, gtk::ShortcutManager;
|
|
}
|
|
|
|
unsafe impl Send for ReSetWindow {}
|
|
|
|
unsafe impl Sync for ReSetWindow {}
|
|
|
|
impl ReSetWindow {
|
|
pub fn new(app: &Application) -> Rc<Self> {
|
|
app.set_accels_for_action("win.search", &["<Ctrl>F"]);
|
|
app.set_accels_for_action("win.close", &["<Ctrl>Q"]);
|
|
app.set_accels_for_action("win.about", &["<Ctrl>H"]);
|
|
// implemented when a proper movement method is found
|
|
// app.set_accels_for_action("win.up", &["<Ctrl>K"]);
|
|
// app.set_accels_for_action("win.right", &["<Ctrl>L"]);
|
|
// app.set_accels_for_action("win.down", &["<Ctrl>J"]);
|
|
// app.set_accels_for_action("win.left", &["<Ctrl>H"]);
|
|
let mut window: Rc<Self> = Rc::new(Object::builder().property("application", app).build());
|
|
window = setup_callback(window);
|
|
window
|
|
}
|
|
|
|
pub fn handle_dynamic_sidebar(&self) {
|
|
let self_imp = self.imp();
|
|
self_imp
|
|
.reset_sidebar_breakpoint
|
|
.set_condition(BreakpointCondition::parse("max-width: 860sp").as_ref().ok());
|
|
self_imp.reset_sidebar_breakpoint.add_setter(
|
|
&Object::from(self_imp.reset_overlay_split_view.get()),
|
|
"collapsed",
|
|
&true.to_value(),
|
|
);
|
|
self_imp.reset_sidebar_breakpoint.add_setter(
|
|
&Object::from(self_imp.reset_sidebar_toggle.get()),
|
|
"visible",
|
|
&true.to_value(),
|
|
);
|
|
}
|
|
|
|
pub fn filter_list(&self) {
|
|
let text = self.imp().reset_search_entry.text().to_string();
|
|
for (main_entry, sub_entriess) in self.imp().sidebar_entries.borrow().iter() {
|
|
if text.is_empty() {
|
|
main_entry.set_visible(true);
|
|
for sub_entry in sub_entriess {
|
|
sub_entry.set_visible(true);
|
|
}
|
|
continue;
|
|
}
|
|
if main_entry
|
|
.imp()
|
|
.name
|
|
.borrow()
|
|
.to_lowercase()
|
|
.contains(&text.to_lowercase())
|
|
{
|
|
main_entry.set_visible(true);
|
|
} else {
|
|
main_entry.set_visible(false);
|
|
}
|
|
for sub_entry in sub_entriess {
|
|
if sub_entry
|
|
.imp()
|
|
.name
|
|
.borrow()
|
|
.to_lowercase()
|
|
.contains(&text.to_lowercase())
|
|
{
|
|
sub_entry.set_visible(true);
|
|
main_entry.set_visible(true);
|
|
} else {
|
|
sub_entry.set_visible(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn toggle_sidebar(&self) {
|
|
if self.imp().reset_overlay_split_view.shows_sidebar() {
|
|
self.imp().reset_overlay_split_view.set_show_sidebar(false);
|
|
} else {
|
|
self.imp().reset_overlay_split_view.set_show_sidebar(true);
|
|
}
|
|
}
|
|
|
|
pub fn setup_sidebar_entries(&self) {
|
|
let self_imp = self.imp();
|
|
let capabilities = get_capabilities();
|
|
let wifi = capabilities.contains(&"WiFi".to_string());
|
|
let bluetooth = capabilities.contains(&"Bluetooth".to_string());
|
|
let audio = capabilities.contains(&"Audio".to_string());
|
|
self_imp.capabilities.set(wifi, bluetooth, audio);
|
|
|
|
let mut sidebar_list = Vec::new();
|
|
|
|
if wifi || bluetooth {
|
|
sidebar_list.push(CONNECTIVITY_SIDEBAR);
|
|
}
|
|
if wifi {
|
|
sidebar_list.push(WIFI_SIDEBAR);
|
|
};
|
|
if bluetooth {
|
|
sidebar_list.push(BLUETOOTH_SIDEBAR);
|
|
};
|
|
if audio {
|
|
sidebar_list.push(AUDIO_SIDEBAR);
|
|
sidebar_list.push(SINK_SIDEBAR);
|
|
sidebar_list.push(SOURCE_SIDEBAR);
|
|
}
|
|
|
|
let mut plugin_sidebar_list = vec![];
|
|
unsafe {
|
|
for plugin in FRONTEND_PLUGINS.iter() {
|
|
let plugin_capabilities = &plugin.capabilities;
|
|
|
|
(plugin.frontend_startup)();
|
|
|
|
let (sidebar_info, plugin_boxes) = (plugin.frontend_data)();
|
|
let listeners = self_imp.listeners.clone();
|
|
|
|
if plugin_capabilities.1 {
|
|
let mut found = false;
|
|
for capability in plugin_capabilities.0.iter() {
|
|
if capabilities.contains(&capability.to_string()) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if !found {
|
|
continue;
|
|
}
|
|
}
|
|
let event = Rc::new(
|
|
move |reset_main: FlowBox,
|
|
position: Rc<RefCell<Position>>,
|
|
boxes: Vec<gtk::Box>| {
|
|
if handle_init(
|
|
listeners.clone(),
|
|
position,
|
|
Position::Custom(String::from(sidebar_info.name)),
|
|
) {
|
|
return;
|
|
}
|
|
reset_main.remove_all();
|
|
for plugin_box in &boxes {
|
|
let frame =
|
|
wrap_in_flow_box_child(SettingBox::new(&plugin_box.clone()));
|
|
reset_main.insert(&frame, -1);
|
|
}
|
|
reset_main.set_max_children_per_line(boxes.len() as u32);
|
|
},
|
|
);
|
|
|
|
plugin_sidebar_list.push(PluginSidebarInfo {
|
|
name: sidebar_info.name,
|
|
icon_name: sidebar_info.icon_name,
|
|
parent: sidebar_info.parent,
|
|
click_event: event,
|
|
plugin_boxes,
|
|
});
|
|
}
|
|
}
|
|
|
|
HANDLE_VOLUME_CLICK(
|
|
&self_imp.capabilities,
|
|
self_imp.listeners.clone(),
|
|
self_imp.reset_main.clone(),
|
|
self_imp.position.clone(),
|
|
);
|
|
|
|
self_imp
|
|
.reset_sidebar_list
|
|
.connect_row_activated(clone!(@ weak self_imp => move |_, _| {
|
|
self_imp.reset_search_entry.set_text("");
|
|
}));
|
|
// TODO: refactor this
|
|
let mut i = 0;
|
|
for info in sidebar_list {
|
|
if info.parent.is_none() && i != 0 {
|
|
self_imp.reset_sidebar_list.insert(&create_separator(), i);
|
|
i += 1;
|
|
}
|
|
let entry = SidebarEntry::new(&info);
|
|
self_imp.reset_sidebar_list.insert(&entry, i);
|
|
i += 1;
|
|
}
|
|
|
|
for info in plugin_sidebar_list {
|
|
if info.parent.is_none() && i != 0 {
|
|
self_imp.reset_sidebar_list.insert(&create_separator(), i);
|
|
i += 1;
|
|
}
|
|
let entry = SidebarEntry::new(&info);
|
|
self_imp.reset_sidebar_list.insert(&entry, i);
|
|
i += 1;
|
|
}
|
|
}
|
|
|
|
pub fn setup_shortcuts(&self) {
|
|
let search_action = ActionEntry::builder("search")
|
|
.activate(move |window: &Self, _, _| {
|
|
let imp = window.imp();
|
|
if !imp.reset_overlay_split_view.shows_sidebar() {
|
|
imp.reset_overlay_split_view.set_show_sidebar(true);
|
|
}
|
|
window.imp().reset_search_entry.grab_focus();
|
|
})
|
|
.build();
|
|
|
|
let banner_action = ActionEntry::builder("banner")
|
|
.parameter_type(Some(&String::static_variant_type()))
|
|
.activate(move |window: &Self, _, text| {
|
|
let imp = window.imp();
|
|
if let Some(text) = text {
|
|
imp.reset_banner.set_title(&text.to_string());
|
|
}
|
|
imp.reset_banner.set_revealed(true);
|
|
})
|
|
.build();
|
|
|
|
let close_action = ActionEntry::builder("close")
|
|
.activate(move |window: &Self, _, _| {
|
|
window.close();
|
|
})
|
|
.build();
|
|
|
|
let error_popup_action = ActionEntry::builder("show_error")
|
|
.activate(move |window: &Self, _, _| {
|
|
window.imp().error_popup.popup();
|
|
})
|
|
.build();
|
|
|
|
let error_popdown_action = ActionEntry::builder("hide_error")
|
|
.activate(move |window: &Self, _, _| {
|
|
window.imp().error_popup.popdown();
|
|
})
|
|
.build();
|
|
|
|
let vim_up = ActionEntry::builder("up")
|
|
.activate(move |window: &Self, _, _| {
|
|
window.child_focus(DirectionType::Up);
|
|
})
|
|
.build();
|
|
|
|
let vim_right = ActionEntry::builder("right")
|
|
.activate(move |window: &Self, _, _| {
|
|
window.child_focus(DirectionType::Right);
|
|
})
|
|
.build();
|
|
|
|
let vim_down = ActionEntry::builder("down")
|
|
.activate(move |window: &Self, _, _| {
|
|
window.child_focus(DirectionType::Down);
|
|
})
|
|
.build();
|
|
|
|
let vim_left = ActionEntry::builder("left")
|
|
.activate(move |window: &Self, _, _| {
|
|
window.child_focus(DirectionType::Left);
|
|
})
|
|
.build();
|
|
|
|
// let clear_initial = ActionEntry::builder("clear_initial")
|
|
// .activate(move |window: &Self, _, _| {
|
|
// let imp = window.imp();
|
|
// for (_, subentries) in imp.sidebar_entries.borrow().iter() {
|
|
// for subentry in subentries {
|
|
// if &*subentry.imp().name.borrow() == "Output" {
|
|
// subentry.set_state_flags(StateFlags::SELECTED, false);
|
|
// }
|
|
// }
|
|
// }
|
|
// })
|
|
// .build();
|
|
|
|
let about_action = ActionEntry::builder("about")
|
|
.activate(move |window: &ReSetWindow, _, _| {
|
|
let dialog = adw::AboutWindow::builder()
|
|
.application_name("ReSet")
|
|
.application_icon("ReSet")
|
|
.developer_name("Xetibo")
|
|
.license("GPL-3.0")
|
|
.license_type(gtk::License::Gpl30)
|
|
.website("https://github.com/Xetibo/ReSet")
|
|
.issue_url("https://github.com/Xetibo/ReSet/issues")
|
|
.version(VERSION)
|
|
.transient_for(window)
|
|
.modal(true)
|
|
.copyright("© 2022-2023 Xetibo")
|
|
.developers(vec!["DashieTM".to_string(), "Takotori".to_string()])
|
|
.designers(vec!["DashieTM".to_string(), "Takotori".to_string()])
|
|
.build();
|
|
// window.imp().reset_popover_menu.popdown();
|
|
dialog.present();
|
|
})
|
|
.build();
|
|
|
|
self.add_action_entries([
|
|
search_action,
|
|
banner_action,
|
|
close_action,
|
|
about_action,
|
|
vim_up,
|
|
vim_right,
|
|
vim_down,
|
|
vim_left,
|
|
error_popup_action,
|
|
error_popdown_action,
|
|
]);
|
|
}
|
|
}
|
|
|
|
fn setup_callback(window: Rc<ReSetWindow>) -> Rc<ReSetWindow> {
|
|
let self_imp = window.imp();
|
|
let activated_ref = window.clone();
|
|
let search_ref = window.clone();
|
|
let toggle_ref = window.clone();
|
|
let close_ref = window.clone();
|
|
|
|
self_imp
|
|
.reset_search_entry
|
|
.connect_search_changed(move |_| {
|
|
search_ref.filter_list();
|
|
});
|
|
|
|
self_imp.reset_sidebar_toggle.connect_clicked(move |_| {
|
|
toggle_ref.toggle_sidebar();
|
|
});
|
|
|
|
self_imp
|
|
.reset_sidebar_list
|
|
.connect_row_activated(move |_, y| {
|
|
let imp = activated_ref.imp();
|
|
let result = y.downcast_ref::<SidebarEntry>().unwrap();
|
|
{
|
|
let mut default_entry = imp.default_entry.borrow_mut();
|
|
if default_entry.is_some() {
|
|
default_entry
|
|
.clone()
|
|
.unwrap()
|
|
.set_state_flags(StateFlags::NORMAL, true);
|
|
*default_entry = None;
|
|
}
|
|
}
|
|
let click_event = result.imp().on_click_event.borrow();
|
|
if let Some(event) = click_event.on_click_event {
|
|
event(
|
|
&imp.capabilities,
|
|
imp.listeners.clone(),
|
|
imp.reset_main.get(),
|
|
imp.position.clone(),
|
|
);
|
|
} else {
|
|
let event = click_event.on_plugin_click_event.clone();
|
|
event(
|
|
imp.reset_main.get(),
|
|
imp.position.clone(),
|
|
result.imp().plugin_boxes.borrow().clone(),
|
|
);
|
|
}
|
|
});
|
|
|
|
self_imp.reset_close.connect_clicked(move |_| {
|
|
close_ref.close();
|
|
});
|
|
|
|
self_imp.reset_banner.connect_button_clicked(|banner| {
|
|
banner.set_revealed(false);
|
|
banner.set_title("Info");
|
|
});
|
|
|
|
window
|
|
}
|
|
|
|
pub fn create_separator() -> ListBoxRow {
|
|
let separator: gtk::Separator = gtk::Separator::builder()
|
|
.margin_bottom(3)
|
|
.margin_top(3)
|
|
.orientation(Orientation::Horizontal)
|
|
.accessible_role(AccessibleRole::Separator)
|
|
.can_focus(false)
|
|
.build();
|
|
ListBoxRow::builder()
|
|
.child(&separator)
|
|
.selectable(false)
|
|
.activatable(false)
|
|
.can_target(false)
|
|
.accessible_role(AccessibleRole::Separator)
|
|
.build()
|
|
}
|
|
|
|
fn handle_init(
|
|
listeners: Arc<Listeners>,
|
|
position: Rc<RefCell<Position>>,
|
|
clicked_position: Position,
|
|
) -> bool {
|
|
{
|
|
let mut pos_borrow = position.borrow_mut();
|
|
if *pos_borrow == clicked_position {
|
|
return true;
|
|
}
|
|
*pos_borrow = clicked_position;
|
|
}
|
|
listeners.stop_network_listener();
|
|
listeners.stop_audio_listener();
|
|
listeners.stop_bluetooth_listener();
|
|
false
|
|
}
|
|
|
|
fn wrap_in_flow_box_child(widget: SettingBox) -> FlowBoxChild {
|
|
let frame = Frame::new(None);
|
|
frame.set_child(Some(&widget));
|
|
frame.add_css_class("resetSettingFrame");
|
|
FlowBoxChild::builder()
|
|
.child(&frame)
|
|
.halign(Align::Fill)
|
|
.valign(Align::Start)
|
|
.build()
|
|
}
|