add example plugin

should be working now
add plugins to sidebar
add plugin system base
Create function signatures for plugins
Update crates
This commit is contained in:
takotori 2024-03-17 14:56:48 +01:00
parent 59fe7fc454
commit a9e0758435
27 changed files with 468 additions and 335 deletions

View file

@ -7,13 +7,14 @@ repository = "https://github.com/Xetibo/ReSet"
license = "GPL-3.0-only"
[dependencies]
reset_daemon = "1.0.1"
re_set-lib = "1.0.0"
adw = { version = "0.5.3", package = "libadwaita", features = ["v1_4"] }
#reset_daemon = "1.1.0"
re_set-lib = { git = "https://github.com/Xetibo/ReSet-Lib" }
reset_daemon = { git = "https://github.com/Xetibo/ReSet-Daemon", branch = "dashie" }
adw = { version = "0.6.0", package = "libadwaita", features = ["v1_4"] }
dbus = "0.9.7"
gtk = { version = "0.7.3", package = "gtk4", features = ["v4_12"] }
glib = "0.18.3"
tokio = { version = "1.33.0", features = [
gtk = { version = "0.8.1", package = "gtk4", features = ["v4_12"] }
glib = "0.19.3"
tokio = { version = "1.36.0", features = [
"rt",
"time",
"net",
@ -21,8 +22,8 @@ tokio = { version = "1.33.0", features = [
"rt-multi-thread",
"sync",
] }
fork = "0.1.22"
fork = "0.1.23"
ipnetwork = "0.20.0"
[build-dependencies]
glib-build-tools = "0.18.0"
glib-build-tools = "0.19.0"

View file

@ -0,0 +1,13 @@
[package]
name = "better_test_plugin"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["dylib"]
[dependencies]
re_set-lib = { git = "https://github.com/Xetibo/ReSet-Lib" }
gtk = { version = "0.8.1", package = "gtk4", features = ["v4_12"] }
dbus = "0.9.7"
glib = "0.19.3"

View file

@ -0,0 +1,84 @@
use std::sync::Arc;
use std::time::Duration;
use dbus::blocking::Connection;
use dbus::Error;
use gtk::{gio, Orientation};
use gtk::prelude::{BoxExt, ButtonExt};
use re_set_lib::utils::plugin::{PluginCapabilities, PluginImplementation, PluginTestFunc, SidebarInfo};
pub const BASE: &str = "org.Xetibo.ReSet.Daemon";
pub const DBUS_PATH: &str = "/org/Xebito/ReSet/Plugins/test";
pub const INTERFACE: &str = "org.Xetibo.ReSet.TestPlugin";
#[no_mangle]
#[allow(improper_ctypes_definitions)]
pub extern "C" fn capabilities() -> PluginCapabilities {
println!("frontend capabilities called");
PluginCapabilities::new(vec!["frontend test"], PluginImplementation::Frontend)
}
#[no_mangle]
pub extern "C" fn frontend_startup() {
println!("frontend startup called");
}
#[no_mangle]
pub extern "C" fn frontend_shutdown() {
println!("frontend shutdown called");
}
#[no_mangle]
#[allow(improper_ctypes_definitions)]
pub extern "C" fn frontend_data() -> (SidebarInfo, Vec<gtk::Box>) {
println!("frontend data called");
let info = SidebarInfo {
name: "test",
icon_name: "microphone-disabled-symbolic",
parent: None,
};
let box1 = gtk::Box::builder().orientation(Orientation::Vertical).build();
let box2 = gtk::Box::builder().orientation(Orientation::Horizontal).build();
let label = Arc::new(LabelWrapper {
label: gtk::Label::builder().label("Hello, World!").build(),
});
let label2 = gtk::Label::builder().label("Bye, World!").build();
let button = gtk::Button::builder().label("Click me!").build();
box1.append(&label.label);
box2.append(&label2);
box2.append(&button);
button.connect_clicked(move |_| {
let label = Arc::clone(&label);
gio::spawn_blocking(move || {
let conn = Connection::new_session().unwrap();
let proxy = conn.with_proxy(BASE, DBUS_PATH, Duration::from_millis(1000));
let res: Result<(String, u32), Error> = proxy.method_call(INTERFACE, "Test", ());
let (text, age) = res.unwrap();
label.label.set_text(&format!("Name: {}, Age: {}", text, age));
});
});
let boxes = vec![
box1, box2,
];
(info, boxes)
}
#[no_mangle]
#[allow(improper_ctypes_definitions)]
pub extern "C" fn frontend_tests() -> Vec<PluginTestFunc> {
println!("frontend tests called");
vec![]
}
pub struct LabelWrapper {
label: gtk::Label,
}
unsafe impl Send for LabelWrapper {}
unsafe impl Sync for LabelWrapper {}

View file

@ -10,7 +10,8 @@ use adw::prelude::{ButtonExt, ComboRowExt, PreferencesRowExt, RangeExt};
use dbus::blocking::Connection;
use dbus::Error;
use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, Cast, Propagation};
use glib::{clone, Propagation};
use glib::prelude::Cast;
use gtk::{gio, StringObject};
use re_set_lib::audio::audio_structures::OutputStream;

View file

@ -4,7 +4,8 @@ use std::{
};
use adw::prelude::{ComboRowExt, PreferencesRowExt};
use glib::{subclass::types::ObjectSubclassIsExt, Cast, ControlFlow, Propagation};
use glib::{subclass::types::ObjectSubclassIsExt, ControlFlow, Propagation};
use glib::prelude::Cast;
use gtk::{
gio,
prelude::{BoxExt, ButtonExt, CheckButtonExt, ListBoxRowExt, RangeExt},

View file

@ -10,7 +10,8 @@ use adw::prelude::{ButtonExt, ComboRowExt, PreferencesRowExt, RangeExt};
use dbus::blocking::Connection;
use dbus::Error;
use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, Cast, Propagation};
use glib::{clone, Propagation};
use glib::prelude::Cast;
use gtk::{gio, StringObject};
use re_set_lib::audio::audio_structures::InputStream;

View file

@ -7,7 +7,8 @@ use adw::{
prelude::{ComboRowExt, PreferencesRowExt},
ComboRow,
};
use glib::{subclass::types::ObjectSubclassIsExt, Cast, Propagation};
use glib::{subclass::types::ObjectSubclassIsExt, Propagation};
use glib::prelude::Cast;
use gtk::{
gio,
prelude::{BoxExt, ButtonExt, CheckButtonExt, ListBoxRowExt, RangeExt},

View file

@ -5,7 +5,8 @@ use adw::prelude::{ComboRowExt, PreferencesRowExt};
use dbus::blocking::Connection;
use dbus::Error;
use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, Cast};
use glib::{clone};
use glib::prelude::Cast;
use gtk::{gio, StringList, StringObject};
use components::utils::create_dropdown_label_factory;

View file

@ -1,5 +1,6 @@
use crate::components::base::list_entry_impl;
use adw::glib::{IsA, Object};
use adw::glib::{Object};
use glib::prelude::IsA;
use gtk::prelude::ListBoxRowExt;
use gtk::Widget;

View file

@ -1,11 +1,12 @@
use crate::components::base::setting_box_impl;
use adw::glib::{IsA, Object};
use adw::glib::{Object};
use glib::prelude::IsA;
use gtk::prelude::BoxExt;
use gtk::Widget;
glib::wrapper! {
pub struct SettingBox(ObjectSubclass<setting_box_impl::SettingBox>)
@extends gtk::Box, gtk::Widget,
@extends gtk::Box, Widget,
@implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget;
}

View file

@ -24,6 +24,7 @@ pub enum Position {
Audio,
AudioOutput,
AudioInput,
Custom(String),
#[default]
Home,
}

View file

@ -8,7 +8,9 @@ use adw::subclass::prelude::ObjectSubclassIsExt;
use dbus::blocking::Connection;
use dbus::message::SignalArgs;
use dbus::{Error, Path};
use glib::{clone, Cast, ControlFlow, PropertySet};
use glib::{clone, ControlFlow};
use glib::prelude::Cast;
use glib::property::PropertySet;
use gtk::glib::Variant;
use gtk::prelude::{ActionableExt, ButtonExt, ListBoxRowExt, WidgetExt};
use gtk::{gio, StringObject};

View file

@ -4,3 +4,4 @@ pub mod bluetooth;
pub mod utils;
pub mod wifi;
pub mod window;
mod plugin;

View file

@ -0,0 +1,30 @@
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use gtk::FlowBox;
use re_set_lib::utils::plugin::SidebarInfo;
use crate::components::base::utils::{Listeners, Position};
extern "C" {
pub fn startup() -> SidebarInfo;
pub fn shutdown();
pub fn run_test();
}
pub struct ReSetSidebarInfo {
pub name: &'static str,
pub icon_name: &'static str,
pub parent: Option<&'static str>,
pub click_event: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>),
}
#[repr(C)]
pub struct PluginSidebarInfo {
pub name: &'static str,
pub icon_name: &'static str,
pub parent: Option<&'static str>,
pub click_event: Rc<dyn Fn(FlowBox, Rc<RefCell<Position>>, Vec<gtk::Box>)>,
pub plugin_boxes: Vec<gtk::Box>,
}

View file

@ -0,0 +1 @@
pub mod function;

View file

@ -1,7 +1,8 @@
use adw::gdk::pango::EllipsizeMode;
use adw::prelude::ListModelExtManual;
use adw::{ActionRow, ComboRow};
use glib::{Cast, Object};
use glib::{Object};
use glib::prelude::Cast;
use gtk::prelude::{GObjectPropertyExpressionExt, ListBoxRowExt, ListItemExt, WidgetExt};
use gtk::{Align, SignalListItemFactory, StringObject};

View file

@ -11,7 +11,8 @@ use adw::prelude::{ActionRowExt, ButtonExt, PreferencesGroupExt, PreferencesRowE
use dbus::blocking::Connection;
use dbus::{Error, Path};
use glib::subclass::types::ObjectSubclassIsExt;
use glib::{clone, PropertySet};
use glib::{clone};
use glib::property::PropertySet;
use gtk::prelude::{BoxExt, ListBoxRowExt};
use gtk::{gio, Align, Button, Orientation};

View file

@ -14,7 +14,9 @@ use dbus::blocking::Connection;
use dbus::message::SignalArgs;
use dbus::Error;
use dbus::Path;
use glib::{clone, Cast, ControlFlow, PropertySet};
use glib::{clone, ControlFlow};
use glib::prelude::Cast;
use glib::property::PropertySet;
use gtk::glib::Variant;
use gtk::prelude::ActionableExt;
use gtk::{gio, StringList, StringObject};

View file

@ -4,12 +4,13 @@ use std::time::Duration;
use crate::components::utils::{BASE, DBUS_PATH, WIRELESS};
use crate::components::wifi::utils::get_connection_settings;
use adw::glib::{Object, PropertySet};
use adw::glib::{Object};
use adw::prelude::{ActionRowExt, ButtonExt, EditableExt, PopoverExt, PreferencesRowExt};
use adw::subclass::prelude::ObjectSubclassIsExt;
use dbus::blocking::Connection;
use dbus::Error;
use glib::clone;
use glib::property::PropertySet;
use gtk::prelude::{BoxExt, ListBoxRowExt, WidgetExt};
use gtk::{gio, Align, Button, Image, Orientation};
use re_set_lib::network::network_structures::{AccessPoint, WifiStrength};

View file

@ -1,7 +1,8 @@
use std::sync::Arc;
use adw::prelude::{ComboRowExt, PreferencesGroupExt, PreferencesRowExt};
use glib::{subclass::types::ObjectSubclassIsExt, PropertySet};
use glib::{subclass::types::ObjectSubclassIsExt};
use glib::property::PropertySet;
use gtk::prelude::WidgetExt;
use re_set_lib::{
network::network_structures::WifiStrength,

View file

@ -10,7 +10,8 @@ use adw::prelude::{ActionRowExt, ComboRowExt, PreferencesGroupExt};
use adw::subclass::prelude::ObjectSubclassIsExt;
use dbus::arg::PropMap;
use dbus::{Error, Path};
use glib::{clone, PropertySet};
use glib::{clone};
use glib::property::PropertySet;
use gtk::prelude::{ActionableExt, ButtonExt, EditableExt, ListBoxRowExt, WidgetExt};
use re_set_lib::network::connection::{
Connection, DNSMethod4, DNSMethod6, Enum, KeyManagement, TypeSettings,

View file

@ -162,60 +162,3 @@ fn handle_init(
listeners.stop_bluetooth_listener();
false
}
// for future implementations
// pub const HANDLE_VPN_CLICK: fn(Arc<Listeners>, FlowBox) =
// |listeners: Arc<Listeners>, resetMain: FlowBox| {
// listeners.stop_network_listener();
// listeners.stop_bluetooth_listener();
// listeners.stop_audio_listener();
// let label = Label::new(Some("not implemented yet"));
// resetMain.remove_all();
// resetMain.insert(&label, -1);
// resetMain.set_max_children_per_line(1);
// };
//
// pub const HANDLE_PERIPHERALS_CLICK: fn(Arc<Listeners>, FlowBox) =
// |listeners: Arc<Listeners>, resetMain: FlowBox| {
// listeners.stop_network_listener();
// listeners.stop_audio_listener();
// listeners.stop_bluetooth_listener();
// let label = Label::new(Some("not implemented yet"));
// resetMain.remove_all();
// resetMain.insert(&label, -1);
// resetMain.set_max_children_per_line(1);
// };
//
// pub const HANDLE_MONITOR_CLICK: fn(Arc<Listeners>, FlowBox) =
// |listeners: Arc<Listeners>, resetMain: FlowBox| {
// listeners.stop_network_listener();
// listeners.stop_audio_listener();
// listeners.stop_bluetooth_listener();
// let label = Label::new(Some("not implemented yet"));
// resetMain.remove_all();
// resetMain.insert(&label, -1);
// resetMain.set_max_children_per_line(1);
// };
//
// pub const HANDLE_MOUSE_CLICK: fn(Arc<Listeners>, FlowBox) =
// |listeners: Arc<Listeners>, resetMain: FlowBox| {
// listeners.stop_network_listener();
// listeners.stop_audio_listener();
// listeners.stop_bluetooth_listener();
// let label = Label::new(Some("not implemented yet"));
// resetMain.remove_all();
// resetMain.insert(&label, -1);
// resetMain.set_max_children_per_line(1);
// };
//
// pub const HANDLE_KEYBOARD_CLICK: fn(Arc<Listeners>, FlowBox) =
// |listeners: Arc<Listeners>, resetMain: FlowBox| {
// listeners.stop_network_listener();
// listeners.stop_audio_listener();
// listeners.stop_bluetooth_listener();
// let label = Label::new(Some("not implemented yet"));
// resetMain.remove_all();
// resetMain.insert(&label, -1);
// resetMain.set_max_children_per_line(1);
// };
//

View file

@ -1,17 +1,22 @@
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use adw::BreakpointCondition;
use adw::glib::clone;
use adw::subclass::prelude::ObjectSubclassIsExt;
use adw::BreakpointCondition;
use glib::Object;
use gtk::{AccessibleRole, Align, Application, FlowBox, FlowBoxChild, Frame, gio, ListBoxRow, Orientation, StateFlags};
use gtk::{DirectionType, prelude::*};
use gtk::gio::ActionEntry;
use gtk::{gio, AccessibleRole, Application, 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, ReSetSidebarInfo};
use crate::components::window::handle_sidebar_click::*;
use crate::components::window::reset_window_impl;
use crate::components::window::sidebar_entry::SidebarEntry;
use crate::components::window::sidebar_entry_impl::Categories;
glib::wrapper! {
pub struct ReSetWindow(ObjectSubclass<reset_window_impl::ReSetWindow>)
@ -39,6 +44,176 @@ impl ReSetWindow {
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 sidebar_list = vec![
ReSetSidebarInfo {
name: "Connectivity",
icon_name: "network-wired-symbolic",
parent: None,
click_event: HANDLE_CONNECTIVITY_CLICK,
},
ReSetSidebarInfo {
name: "WiFi",
icon_name: "network-wireless-symbolic",
parent: Some("Connectivity"),
click_event: HANDLE_WIFI_CLICK,
},
ReSetSidebarInfo {
name: "Bluetooth",
icon_name: "bluetooth-symbolic",
parent: Some("Connectivity"),
click_event: HANDLE_BLUETOOTH_CLICK,
},
ReSetSidebarInfo {
name: "Audio",
icon_name: "audio-headset-symbolic",
parent: None,
click_event: HANDLE_AUDIO_CLICK,
},
ReSetSidebarInfo {
name: "Output",
icon_name: "audio-volume-high-symbolic",
parent: Some("Audio"),
click_event: HANDLE_VOLUME_CLICK,
},
ReSetSidebarInfo {
name: "Input",
icon_name: "audio-input-microphone-symbolic",
parent: Some("Audio"),
click_event: HANDLE_MICROPHONE_CLICK,
},
];
let mut plugin_sidebar_list = vec![];
unsafe {
for plugin in FRONTEND_PLUGINS.iter() {
let (sidebar_info, plugin_boxes) = (plugin.frontend_data)();
let listeners = self_imp.listeners.clone();
(plugin.frontend_startup)();
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.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("");
}));
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_plugin(&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, _, _| {
@ -139,221 +314,8 @@ impl ReSetWindow {
error_popdown_action,
]);
}
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 mut sidebar_entries = self_imp.sidebar_entries.borrow_mut();
let connectivity_list = vec![
Rc::new(SidebarEntry::new(
"WiFi",
"network-wireless-symbolic",
Categories::Connectivity,
true,
HANDLE_WIFI_CLICK,
)),
Rc::new(SidebarEntry::new(
"Bluetooth",
"bluetooth-symbolic",
Categories::Connectivity,
true,
HANDLE_BLUETOOTH_CLICK,
)),
// uncommented when VPN is implemented
// SidebarEntry::new(
// "VPN",
// "network-vpn-symbolic",
// Categories::Connectivity,
// true,
// HANDLE_VPN_CLICK,
// ),
];
sidebar_entries.push((
Rc::new(SidebarEntry::new(
"Connectivity",
"network-wired-symbolic",
Categories::Connectivity,
false,
HANDLE_CONNECTIVITY_CLICK,
)),
connectivity_list,
));
let output = Rc::new(SidebarEntry::new(
"Output",
"audio-volume-high-symbolic",
Categories::Audio,
true,
HANDLE_VOLUME_CLICK,
));
output.set_receives_default(true);
let audio_list = vec![
output,
Rc::new(SidebarEntry::new(
"Input",
"audio-input-microphone-symbolic",
Categories::Audio,
true,
HANDLE_MICROPHONE_CLICK,
)),
];
sidebar_entries.push((
Rc::new(SidebarEntry::new(
"Audio",
"audio-headset-symbolic",
Categories::Audio,
false,
HANDLE_AUDIO_CLICK,
)),
audio_list,
));
// uncommented when implemented
// let peripheralsList = vec![
// SidebarEntry::new(
// "Displays",
// "video-display-symbolic",
// Categories::Peripherals,
// true,
// HANDLE_MONITOR_CLICK,
// ),
// SidebarEntry::new(
// "Mouse",
// "input-mouse-symbolic",
// Categories::Peripherals,
// true,
// HANDLE_MOUSE_CLICK,
// ),
// SidebarEntry::new(
// "Keyboard",
// "input-keyboard-symbolic",
// Categories::Peripherals,
// true,
// HANDLE_KEYBOARD_CLICK,
// ),
// ];
// let home = SidebarEntry::new(
// "Home",
// "preferences-system-devices-symbolic",
// Categories::Peripherals,
// false,
// HANDLE_VOLUME_CLICK,
// );
//
// sidebar_entries.push((home, Vec::new()));
(HANDLE_VOLUME_CLICK)(
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("");
}));
for (main_entry, sub_entries) in sidebar_entries.iter() {
self_imp.reset_sidebar_list.append(&**main_entry);
for sub_entry in sub_entries {
// TODO change this to home when home offers dynamic selection
// this is just a placeholder for now, hence hardcoded
if &*sub_entry.imp().name.borrow() == "Output" {
self_imp.reset_sidebar_list.append(&**sub_entry);
self_imp.default_entry.replace(Some(sub_entry.clone()));
sub_entry.grab_focus();
sub_entry.set_state_flags(StateFlags::SELECTED, false);
} else {
self_imp.reset_sidebar_list.append(&**sub_entry);
}
}
let separator = gtk::Separator::builder()
.margin_bottom(3)
.margin_top(3)
.orientation(Orientation::Horizontal)
.accessible_role(AccessibleRole::Separator)
.can_focus(false)
.build();
let separator_row = ListBoxRow::builder()
.child(&separator)
.selectable(false)
.activatable(false)
.can_target(false)
// .focusable(false)
.accessible_role(AccessibleRole::Separator)
.build();
// TODO how to simply skip this ?
self_imp.reset_sidebar_list.append(&separator_row);
}
}
}
fn setup_callback(window: Rc<ReSetWindow>) -> Rc<ReSetWindow> {
let self_imp = window.imp();
let activated_ref = window.clone();
@ -386,12 +348,21 @@ fn setup_callback(window: Rc<ReSetWindow>) -> Rc<ReSetWindow> {
*default_entry = None;
}
}
let click_event = result.imp().on_click_event.borrow().on_click_event;
(click_event)(
imp.listeners.clone(),
imp.reset_main.get(),
imp.position.clone(),
);
let click_event = result.imp().on_click_event.borrow();
if let Some(event) = click_event.on_click_event {
event(
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 |_| {
@ -399,3 +370,49 @@ fn setup_callback(window: Rc<ReSetWindow>) -> Rc<ReSetWindow> {
});
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()
}

View file

@ -2,9 +2,9 @@ use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use adw::glib::StaticTypeExt;
use adw::subclass::prelude::AdwApplicationWindowImpl;
use adw::{Breakpoint, OverlaySplitView};
use glib::prelude::StaticTypeExt;
use glib::subclass::InitializingObject;
use gtk::prelude::WidgetExt;
use gtk::subclass::prelude::*;

View file

@ -1,14 +1,13 @@
use std::cell::RefCell;
use std::rc::Rc;
use std::sync::Arc;
use crate::components::base::utils::{Listeners, Position};
use crate::components::window::sidebar_entry_impl;
use crate::components::window::sidebar_entry_impl::{Categories, SidebarAction};
use crate::components::window::sidebar_entry_impl::{SidebarAction};
use adw::subclass::prelude::ObjectSubclassIsExt;
use glib::Object;
use gtk::prelude::*;
use gtk::FlowBox;
use crate::components::plugin::function::{PluginSidebarInfo, ReSetSidebarInfo};
use super::handle_sidebar_click::HANDLE_HOME;
glib::wrapper! {
pub struct SidebarEntry(ObjectSubclass<sidebar_entry_impl::SidebarEntry>)
@ -17,37 +16,62 @@ glib::wrapper! {
}
impl SidebarEntry {
pub fn new(
entry_name: &str,
icon_name: &str,
category: Categories,
is_subcategory: bool,
click_event: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>),
) -> Self {
pub fn new(info: &ReSetSidebarInfo) -> Self {
let entry: SidebarEntry = Object::builder().build();
let entry_imp = entry.imp();
entry_imp.reset_sidebar_label.get().set_text(entry_name);
entry_imp.reset_sidebar_label.get().set_text(info.name);
entry_imp
.reset_sidebar_image
.set_from_icon_name(Some(icon_name));
entry_imp.category.set(category);
entry_imp.is_subcategory.set(is_subcategory);
.set_from_icon_name(Some(info.icon_name));
match &info.parent {
None => {}
Some(parent) => {
let mut name = entry_imp.parent.borrow_mut();
*name = parent.to_string();
entry.child().unwrap().set_margin_start(30);
}
}
{
let mut name = entry_imp.name.borrow_mut();
*name = String::from(entry_name);
*name = info.name.to_string();
let mut action = entry_imp.on_click_event.borrow_mut();
*action = SidebarAction {
on_click_event: click_event,
on_click_event: Some(info.click_event),
on_plugin_click_event: Rc::new(|_,_,_|{}),
};
}
Self::set_margin(&entry);
entry
}
fn set_margin(entry: &SidebarEntry) {
if entry.imp().is_subcategory.get() {
let option = entry.child().unwrap();
option.set_margin_start(30);
pub fn new_plugin(info: &PluginSidebarInfo) -> Self {
let entry: SidebarEntry = Object::builder().build();
let entry_imp = entry.imp();
entry_imp.reset_sidebar_label.get().set_text(info.name);
entry_imp
.reset_sidebar_image
.set_from_icon_name(Some(info.icon_name));
entry_imp.plugin_boxes.borrow_mut().extend(info.plugin_boxes.clone());
match &info.parent {
None => {}
Some(parent) => {
let mut name = entry_imp.parent.borrow_mut();
*name = parent.to_string();
entry.child().unwrap().set_margin_start(30);
}
}
{
let mut name = entry_imp.name.borrow_mut();
*name = info.name.to_string();
let mut action = entry_imp.on_click_event.borrow_mut();
*action = SidebarAction {
on_click_event: None,
on_plugin_click_event: info.click_event.clone(),
};
}
entry
}
}

View file

@ -3,8 +3,8 @@ use std::rc::Rc;
use std::sync::Arc;
use glib::subclass::InitializingObject;
use gtk::subclass::prelude::*;
use gtk::{CompositeTemplate, FlowBox, Image, Label, ListBoxRow};
use gtk::subclass::prelude::*;
use crate::components::base::utils::{Listeners, Position};
use crate::components::window::handle_sidebar_click::HANDLE_HOME;
@ -26,20 +26,22 @@ pub struct SidebarEntry {
pub reset_sidebar_label: TemplateChild<Label>,
#[template_child]
pub reset_sidebar_image: TemplateChild<Image>,
pub category: Cell<Categories>,
pub is_subcategory: Cell<bool>,
pub parent: RefCell<String>,
pub on_click_event: RefCell<SidebarAction>,
pub plugin_boxes: RefCell<Vec<gtk::Box>>,
pub name: RefCell<String>,
}
pub struct SidebarAction {
pub on_click_event: fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>),
pub on_click_event: Option<fn(Arc<Listeners>, FlowBox, Rc<RefCell<Position>>)>,
pub on_plugin_click_event: Rc<dyn Fn(FlowBox, Rc<RefCell<Position>>, Vec<gtk::Box>)>,
}
impl Default for SidebarAction {
fn default() -> Self {
Self {
on_click_event: HANDLE_HOME,
on_click_event: Some(HANDLE_HOME),
on_plugin_click_event: Rc::new(|_,_,_|{}),
}
}
}

View file

@ -68,6 +68,6 @@ async fn daemon_check() {
});
let res = handle.join();
if res.unwrap().is_err() {
run_daemon().await;
run_daemon(vec![String::from("ina")]).await;
}
}