More updating to zbus 4.0.1

This commit is contained in:
Luke D. Jones
2024-02-22 23:49:35 +13:00
parent a44145f487
commit 8e4b7d53f4
50 changed files with 3151 additions and 2932 deletions

View File

@@ -1,178 +0,0 @@
use std::f64::consts::PI;
use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
use egui::{Button, RichText};
use rog_aura::layouts::KeyLayout;
use rog_platform::platform::Properties;
use crate::config::Config;
use crate::error::Result;
use crate::system_state::SystemState;
use crate::{Page, RogDbusClientBlocking};
pub struct RogApp {
pub page: Page,
pub states: Arc<Mutex<SystemState>>,
// TODO: can probably just open and read whenever
pub config: Config,
/// Oscillator in percentage
pub oscillator1: Arc<AtomicU8>,
pub oscillator2: Arc<AtomicU8>,
pub oscillator3: Arc<AtomicU8>,
/// Frequency of oscillation
pub oscillator_freq: Arc<AtomicU8>,
/// A toggle that toggles true/false when the oscillator reaches 0
pub oscillator_toggle: Arc<AtomicBool>,
pub supported_interfaces: Vec<String>,
pub supported_properties: Vec<Properties>,
}
impl RogApp {
/// Called once before the first frame.
pub fn new(
config: Config,
states: Arc<Mutex<SystemState>>,
_cc: &eframe::CreationContext<'_>,
) -> Result<Self> {
let (dbus, _) = RogDbusClientBlocking::new()?;
let supported_interfaces = dbus.proxies().platform().supported_interfaces()?;
let supported_properties = dbus.proxies().platform().supported_properties()?;
// Set up an oscillator to run on a thread.
// Helpful for visual effects like colour pulse.
let oscillator1 = Arc::new(AtomicU8::new(0));
let oscillator2 = Arc::new(AtomicU8::new(0));
let oscillator3 = Arc::new(AtomicU8::new(0));
let oscillator1_1 = oscillator1.clone();
let oscillator1_2 = oscillator2.clone();
let oscillator1_3 = oscillator3.clone();
let oscillator_freq = Arc::new(AtomicU8::new(5));
let oscillator_freq1 = oscillator_freq.clone();
let oscillator_toggle = Arc::new(AtomicBool::new(false));
let oscillator_toggle1 = oscillator_toggle.clone();
std::thread::spawn(move || {
let started = Instant::now();
let mut toggled = false;
loop {
let time = started.elapsed();
// 32 = slow, 16 = med, 8 = fast
let scale = oscillator_freq1.load(Ordering::SeqCst) as f64;
let elapsed1 = (time.as_millis() as f64 + 333.0) / 10000.0;
let elapsed2 = (time.as_millis() as f64 + 666.0) / 10000.0;
let elapsed3 = (time.as_millis() as f64 + 999.0) / 10000.0;
let tmp1 = ((scale * elapsed1 * PI).cos()).abs();
let tmp2 = ((scale * 0.85 * elapsed2 * PI).cos()).abs();
let tmp3 = ((scale * 0.7 * elapsed3 * PI).cos()).abs();
if tmp1 <= 0.1 && !toggled {
let s = oscillator_toggle1.load(Ordering::SeqCst);
oscillator_toggle1.store(!s, Ordering::SeqCst);
toggled = true;
} else if tmp1 > 0.9 {
toggled = false;
}
let tmp1 = (255.0 * tmp1 * 100.0 / 255.0) as u8;
let tmp2 = (255.0 * tmp2 * 100.0 / 255.0) as u8;
let tmp3 = (255.0 * tmp3 * 100.0 / 255.0) as u8;
oscillator1_1.store(tmp1, Ordering::SeqCst);
oscillator1_2.store(tmp2, Ordering::SeqCst);
oscillator1_3.store(tmp3, Ordering::SeqCst);
std::thread::sleep(Duration::from_millis(33));
}
});
Ok(Self {
supported_interfaces,
supported_properties,
states,
page: Page::System,
config,
oscillator1,
oscillator2,
oscillator3,
oscillator_toggle,
oscillator_freq,
})
}
}
impl eframe::App for RogApp {
/// Called each time the UI needs repainting, which may be many times per
/// second. Put your widgets into a `SidePanel`, `TopPanel`,
/// `CentralPanel`, `Window` or `Area`.
fn update(&mut self, ctx: &eframe::egui::Context, frame: &mut eframe::Frame) {
let states = self.states.clone();
if let Ok(mut states) = states.try_lock() {
if states.app_should_update {
states.app_should_update = false;
ctx.request_repaint();
}
}
// Shortcut typical display stuff
if let Ok(mut states) = states.try_lock() {
let layout_testing = states.aura_creation.layout_testing.clone();
if let Some(path) = &layout_testing {
let modified = path.metadata().unwrap().modified().unwrap();
if states.aura_creation.layout_last_modified < modified {
states.aura_creation.layout_last_modified = modified;
// time to reload the config
states.aura_creation.keyboard_layout = KeyLayout::from_file(path).unwrap();
}
self.aura_page(&mut states, ctx);
return;
}
self.top_bar(ctx, frame);
self.side_panel(ctx);
}
let page = self.page;
let mut was_error = false;
if let Ok(mut states) = states.try_lock() {
if let Some(err) = states.error.clone() {
was_error = true;
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading(RichText::new("Error!").size(28.0));
ui.centered_and_justified(|ui| {
ui.label(RichText::new(format!("The error was: {:?}", err)).size(22.0));
});
});
egui::TopBottomPanel::bottom("error_bar")
.default_height(26.0)
.show(ctx, |ui| {
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
if ui
.add(Button::new(RichText::new("Okay").size(20.0)))
.clicked()
{
states.error = None;
}
});
});
}
}
if !was_error {
if let Ok(mut states) = states.try_lock() {
match page {
Page::AppSettings => self.app_settings_page(&mut states, ctx),
Page::System => self.system_page(&mut states, ctx),
Page::AuraEffects => self.aura_page(&mut states, ctx),
Page::AnimeMatrix => self.anime_page(ctx),
Page::FanCurves => self.fan_curve_page(&mut states, ctx),
};
}
}
}
}

View File

@@ -11,7 +11,6 @@ pub enum Error {
XdgVars,
Zbus(zbus::Error),
Notification(notify_rust::error::Error),
Eframe(eframe::Error),
}
impl fmt::Display for Error {
@@ -25,7 +24,6 @@ impl fmt::Display for Error {
Error::XdgVars => write!(f, "XDG environment vars appear unset"),
Error::Zbus(err) => write!(f, "Error: {}", err),
Error::Notification(err) => write!(f, "Notification Error: {}", err),
Error::Eframe(err) => write!(f, "Eframe Error: {}", err),
}
}
}
@@ -55,9 +53,3 @@ impl From<notify_rust::error::Error> for Error {
Error::Notification(err)
}
}
impl From<eframe::Error> for Error {
fn from(err: eframe::Error) -> Self {
Error::Eframe(err)
}
}

View File

@@ -1,23 +1,25 @@
pub mod app;
// These lints need to be allowed due to the generated sources
#![allow(clippy::redundant_clone, clippy::cmp_owned)]
slint::include_modules!();
// Intentionally reexport slint so that GUI consumers don't need to add to
// `Cargo.toml`
use std::fs::{remove_dir_all, File, OpenOptions};
use std::io::{Read, Write};
use std::process::exit;
use std::thread::sleep;
use std::time::Duration;
pub use app::RogApp;
pub use slint;
pub mod cli_options;
pub mod config;
pub mod error;
#[cfg(feature = "mocking")]
pub mod mocking;
pub mod pages;
pub mod startup_error;
pub mod system_state;
pub mod tray;
pub mod update_and_notify;
pub mod widgets;
#[cfg(feature = "mocking")]
pub use mocking::RogDbusClientBlocking;
@@ -44,6 +46,7 @@ pub fn print_versions() {
pub const SHOWING_GUI: u8 = 1;
pub const SHOW_GUI: u8 = 2;
pub const QUIT_APP: u8 = 3;
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum Page {

View File

@@ -1,30 +1,29 @@
use std::borrow::BorrowMut;
use std::env::args;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::thread;
use std::thread::{self, sleep, spawn};
use std::time::Duration;
use eframe::HardwareAcceleration;
use gumdrop::Options;
use log::{debug, error, warn, LevelFilter};
use log::{warn, LevelFilter};
use rog_aura::aura_detection::{LaptopLedData, LedSupportFile};
use rog_aura::layouts::KeyLayout;
use rog_control_center::cli_options::CliStart;
use rog_control_center::config::Config;
use rog_control_center::error::Result;
use rog_control_center::startup_error::AppErrorShow;
use rog_control_center::slint::ComponentHandle;
use rog_control_center::system_state::SystemState;
use rog_control_center::tray::init_tray;
use rog_control_center::update_and_notify::{start_notifications, EnabledNotifications};
use rog_control_center::{
get_ipc_file, on_tmp_dir_exists, print_versions, RogApp, RogDbusClientBlocking, SHOWING_GUI,
SHOW_GUI,
get_ipc_file, on_tmp_dir_exists, print_versions, MainWindow, RogDbusClientBlocking, QUIT_APP,
SHOWING_GUI, SHOW_GUI,
};
#[cfg(not(feature = "mocking"))]
use supergfxctl::zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking;
use tokio::runtime::Runtime;
// use winit::monitor::VideoMode;
// use winit::window::{Fullscreen, WindowLevel};
#[cfg(not(feature = "mocking"))]
const DATA_DIR: &str = "/usr/share/rog-gui/";
@@ -61,44 +60,22 @@ fn main() -> Result<()> {
// Enter the runtime so that `tokio::spawn` is available immediately.
let _enter = rt.enter();
let native_options = eframe::NativeOptions {
vsync: true,
hardware_acceleration: HardwareAcceleration::Preferred,
min_window_size: Some(egui::vec2(980.0, 670.0)),
max_window_size: Some(egui::vec2(980.0, 670.0)),
run_and_return: true,
..Default::default()
};
let (dbus, _) = RogDbusClientBlocking::new()
.map_err(|e| {
eframe::run_native(
"ROG Control Center",
native_options.clone(),
Box::new(move |_| Box::new(AppErrorShow::new(e.to_string()))),
)
.map_err(|e| error!("{e}"))
.ok();
.map_err(|_| {
// TODO: show an error window
})
.unwrap();
let supported_properties = match dbus.proxies().platform().supported_properties() {
Ok(s) => s,
Err(e) => {
eframe::run_native(
"ROG Control Center",
native_options.clone(),
Box::new(move |_| Box::new(AppErrorShow::new(e.to_string()))),
)
.map_err(|e| error!("{e}"))
.ok();
vec![]
Err(_e) => {
// TODO: show an error window
Vec::default()
}
};
// Startup
let mut config = Config::load()?;
let running_in_bg = Arc::new(AtomicBool::new(config.startup_in_background));
if config.startup_in_background {
config.run_in_background = true;
@@ -179,6 +156,7 @@ fn main() -> Result<()> {
Ok(tmp) => tmp,
Err(_) => on_tmp_dir_exists().unwrap(),
};
dbg!();
let states = setup_page_state_and_notifs(
layout_name,
@@ -188,77 +166,107 @@ fn main() -> Result<()> {
&config,
)?;
if cli_parsed.board_name.is_some() || cli_parsed.layout_viewing {
if let Ok(mut lock) = states.lock() {
lock.run_in_bg = false;
running_in_bg.store(false, Ordering::Release);
}
}
if config.enable_tray_icon {
init_tray(supported_properties, states.clone());
}
dbg!();
if let Ok(mut states) = states.lock() {
// For some reason the gui is causing a broke pipe error on dbus send, so
// replace it.
let (asus_dbus, conn) =
rog_dbus::RogDbusClientBlocking::new().expect("Couldn't connect to asusd");
states.asus_dbus = asus_dbus;
let gfx_dbus = GfxProxyBlocking::new(&conn).expect("Couldn't connect to supergfxd");
states.gfx_dbus = gfx_dbus;
}
thread_local! { pub static UI: std::cell::RefCell<Option<MainWindow>> = Default::default()};
i_slint_backend_selector::with_platform(|_| Ok(())).unwrap();
let mut bg_check_spawned = false;
loop {
if !running_in_bg.load(Ordering::Relaxed) {
// blocks until window is closed
let states = states.clone();
let mut ipc_file = get_ipc_file()?;
ipc_file.write_all(&[SHOWING_GUI])?;
eframe::run_native(
"ROG Control Center",
native_options.clone(),
Box::new(move |cc| {
let cfg = Config::load().unwrap();
let app = RogApp::new(cfg, states, cc);
Box::new(app.unwrap())
}),
)?;
dbg!();
thread::spawn(move || {
let mut buf = [0u8; 2];
// blocks until it is read, typically the read will happen after a second
// process writes to the IPC (so there is data to actually read)
loop {
get_ipc_file().unwrap().read_exact(&mut buf).unwrap();
if buf[0] == SHOW_GUI {
println!("Should show window {buf:?}");
let mut ipc_file = get_ipc_file().unwrap();
ipc_file.write_all(&[SHOWING_GUI, 0]).unwrap();
running_in_bg.store(true, Ordering::SeqCst);
bg_check_spawned = false;
}
if let Ok(lock) = states.try_lock() {
if !lock.run_in_bg {
break;
}
if lock.run_in_bg && running_in_bg.load(Ordering::Acquire) && !bg_check_spawned {
let running_in_bg = running_in_bg.clone();
thread::spawn(move || {
let mut buf = [0u8; 4];
// blocks until it is read, typically the read will happen after a second
// process writes to the IPC (so there is data to actually read)
loop {
if get_ipc_file().unwrap().read(&mut buf).is_ok() && buf[0] == SHOW_GUI {
running_in_bg.store(false, Ordering::Release);
debug!("Wait thread got from tray {buf:#?}");
break;
let states = states.clone();
i_slint_core::api::invoke_from_event_loop(move || {
UI.with(|ui| {
let mut ui = ui.borrow_mut();
if let Some(ui) = ui.as_mut() {
ui.window().show().unwrap();
ui.window().on_close_requested(|| {
let mut ipc_file = get_ipc_file().unwrap();
ipc_file.write_all(&[0, 0]).unwrap();
slint::CloseRequestResponse::HideWindow
});
} else {
let newui = setup_window(states.clone());
newui.window().show().unwrap();
println!("New window should be showing now"); // but it isn't
newui.window().on_close_requested(|| {
let mut ipc_file = get_ipc_file().unwrap();
ipc_file.write_all(&[0, 0]).unwrap();
slint::CloseRequestResponse::HideWindow
});
ui.replace(newui);
}
}
});
bg_check_spawned = true;
});
})
.unwrap();
} else if buf[1] == QUIT_APP {
slint::quit_event_loop().unwrap();
} else if buf[0] != SHOWING_GUI {
println!("Should hide window {buf:?}");
i_slint_core::api::invoke_from_event_loop(move || {
UI.with(|ui| {
let mut ui = ui.take();
if let Some(ui) = ui.borrow_mut() {
ui.window().hide().unwrap();
}
});
})
.unwrap();
}
}
});
// Prevent hogging CPU
thread::sleep(Duration::from_millis(500));
}
slint::run_event_loop_until_quit().unwrap();
Ok(())
}
fn setup_window(_states: Arc<Mutex<SystemState>>) -> MainWindow {
// slint::platform::set_platform(Box::new(i_slint_backend_winit::Backend::new().
// unwrap())).unwrap();
let ui = MainWindow::new().unwrap();
// Example of how to do work in another thread.
// The thread itself can keep its own state, and then update vars in the UI
// when required.
let ui_handle = ui.as_weak();
spawn(move || loop {
sleep(Duration::from_secs(1));
// This is where the actual update happens
ui_handle
.upgrade_in_event_loop(move |handle| {
// handle.set_counter(handle.get_counter() + 1);
use i_slint_backend_winit::WinitWindowAccessor;
handle
.window()
.with_winit_window(|winit_window: &winit::window::Window| {
// winit_window.set_fullscreen(Some(Fullscreen::Borderless(None)));
if !winit_window.has_focus() {
// slint::quit_event_loop().unwrap();
// handle.hide().unwrap();
}
});
})
.ok();
});
ui.on_exit_app(move || {
slint::quit_event_loop().unwrap();
});
ui
}
fn setup_page_state_and_notifs(
layout_testing: Option<PathBuf>,
keyboard_layout: KeyLayout,

View File

@@ -1,9 +0,0 @@
use crate::RogApp;
impl RogApp {
pub fn anime_page(&mut self, ctx: &eframe::egui::Context) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.label("In progress");
});
}
}

View File

@@ -1,24 +0,0 @@
use crate::system_state::SystemState;
use crate::widgets::app_settings;
use crate::RogApp;
impl RogApp {
pub fn app_settings_page(&mut self, states: &mut SystemState, ctx: &eframe::egui::Context) {
let Self { config, .. } = self;
egui::CentralPanel::default().show(ctx, |ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
ui.spacing_mut().item_spacing = egui::vec2(8.0, 10.0);
let rect = ui.available_rect_before_wrap();
egui::Grid::new("grid_of_bits")
.min_col_width(rect.width() / 2.0)
.show(ui, |ui| {
ui.vertical(|ui| {
ui.separator();
app_settings(config, states, ui);
});
});
})
});
}
}

View File

@@ -1,83 +0,0 @@
use std::sync::atomic::Ordering;
use std::time::Duration;
use egui::Color32;
use rog_aura::{AuraEffect, AuraModeNum};
use crate::system_state::SystemState;
use crate::widgets::{aura_modes_group, keyboard};
use crate::RogApp;
impl RogApp {
pub fn aura_page(&mut self, states: &mut SystemState, ctx: &eframe::egui::Context) {
let Self {
oscillator1,
oscillator2,
oscillator3,
oscillator_freq,
..
} = self;
let red = oscillator1.load(Ordering::SeqCst) as u32;
let green = oscillator2.load(Ordering::SeqCst) as u32;
let blue = oscillator3.load(Ordering::SeqCst) as u32;
states.aura.nudge_wave(red as u8, green as u8, blue as u8);
// let osc = c.r * 255 / osc;
let c1 = states
.aura
.modes
.get(&states.aura.current_mode)
.unwrap_or(&AuraEffect::default())
.colour1;
let c2 = states
.aura
.modes
.get(&states.aura.current_mode)
.unwrap_or(&AuraEffect::default())
.colour2;
let mut colour = Color32::from_rgb(c1.r, c1.g, c1.b);
if states.aura.current_mode == AuraModeNum::Pulse {
colour = Color32::from_rgb(
(red * c1.r as u32 / 100) as u8,
(red * c1.g as u32 / 100) as u8,
(red * c1.b as u32 / 100) as u8,
);
} else if states.aura.current_mode == AuraModeNum::Breathe {
if self.oscillator_toggle.load(Ordering::SeqCst) {
colour = Color32::from_rgb(
(red * c2.r as u32 / 100) as u8,
(red * c2.g as u32 / 100) as u8,
(red * c2.b as u32 / 100) as u8,
);
} else {
colour = Color32::from_rgb(
(red * c1.r as u32 / 100) as u8,
(red * c1.g as u32 / 100) as u8,
(red * c1.b as u32 / 100) as u8,
);
}
} else if states.aura.current_mode == AuraModeNum::Strobe {
colour = Color32::from_rgb(
(red * 255 / 100) as u8,
(green * 255 / 100) as u8,
(blue * 255 / 100) as u8,
);
}
// TODO: animation of colour changes/periods/blending
egui::CentralPanel::default().show(ctx, |ui| {
aura_modes_group(states, oscillator_freq, ui);
keyboard(
ui,
&states.aura_creation.keyboard_layout,
&mut states.aura,
colour,
);
});
// Only do repaint request if on this page
ctx.request_repaint_after(Duration::from_millis(33));
}
}

View File

@@ -1,92 +0,0 @@
use egui::{RichText, Ui};
use rog_platform::platform::ThrottlePolicy;
use crate::system_state::{FanCurvesState, SystemState};
use crate::widgets::fan_graphs;
use crate::{RogApp, RogDbusClientBlocking};
impl RogApp {
pub fn fan_curve_page(&mut self, states: &mut SystemState, ctx: &eframe::egui::Context) {
if let Some(mut throttle) = states.bios.throttle {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Custom fan curves");
Self::fan_curve(
&mut throttle,
&mut states.fan_curves,
&states.asus_dbus,
&mut states.error,
ui,
);
fan_graphs(
&mut states.fan_curves,
&states.asus_dbus,
&mut states.error,
ui,
);
});
}
}
fn fan_curve(
current: &mut ThrottlePolicy,
curves: &mut FanCurvesState,
dbus: &RogDbusClientBlocking<'_>,
do_error: &mut Option<String>,
ui: &mut Ui,
) {
ui.separator();
let mut changed = false;
ui.horizontal(|ui| {
ui.label("Current profile: ");
ui.label(RichText::new(format!("{}", current)).strong());
});
ui.horizontal(|ui| {
ui.label("Enabled fan-curves: ");
let mut checked = false;
let mut label = String::default();
if let Some(curves) = curves.curves.get_mut(current) {
for curve in curves.iter() {
label.push_str(&<&str>::from(curve.fan).to_ascii_uppercase());
label.push(' ');
if curve.enabled {
// TODO: it's possible to set just one fan to active
checked = true;
}
}
}
if ui
.add(egui::Checkbox::new(
&mut checked,
RichText::new(label).strong(),
))
.changed()
{
dbus.proxies()
.fan_curves()
.set_fan_curves_enabled(*current, checked)
.map_err(|err| {
*do_error = Some(err.to_string());
})
.ok();
changed = true;
}
});
if changed {
let selected_profile = curves.show_curve;
let selected_pu = curves.show_graph;
match FanCurvesState::new(dbus) {
Ok(f) => *curves = f,
Err(e) => *do_error = Some(e.to_string()),
}
curves.show_curve = selected_profile;
curves.show_graph = selected_pu;
}
}
}

View File

@@ -1,5 +0,0 @@
mod anime_page;
mod app_settings;
mod aura_page;
mod fan_curve_page;
mod system_page;

View File

@@ -1,50 +0,0 @@
use crate::system_state::SystemState;
use crate::widgets::{anime_power_group, aura_power_group, platform_profile, rog_bios_group};
use crate::RogApp;
impl RogApp {
pub fn system_page(&mut self, states: &mut SystemState, ctx: &eframe::egui::Context) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Laptop settings");
egui::ScrollArea::vertical().show(ui, |ui| {
ui.spacing_mut().item_spacing = egui::vec2(8.0, 10.0);
let rect = ui.available_rect_before_wrap();
egui::Grid::new("grid_of_bits")
.min_col_width(rect.width() / 2.0)
.show(ui, |ui| {
ui.vertical(|ui| {
ui.separator();
// if self.supported_interfaces {
platform_profile(states, ui);
// }
});
ui.vertical(|ui| {
ui.separator();
if self.supported_interfaces.contains(&"Aura".to_string()) {
aura_power_group(states, ui);
}
});
ui.end_row();
ui.vertical(|ui| {
ui.separator();
rog_bios_group(states, ui);
});
ui.end_row();
ui.vertical(|ui| {
ui.separator();
if self.supported_interfaces.contains(&"Anime".to_string()) {
anime_power_group(states, ui);
}
});
ui.vertical(|ui| {
ui.separator();
});
ui.end_row();
});
});
});
}
}

View File

@@ -1,38 +0,0 @@
use egui::RichText;
pub struct AppErrorShow {
error: String,
}
impl AppErrorShow {
pub fn new(error: String) -> Self {
Self { error }
}
}
impl eframe::App for AppErrorShow {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("ROG ERROR");
ui.centered_and_justified(|ui| {
ui.label(RichText::new(format!("The error was: {:?}", self.error)).size(22.0));
});
// egui::TopBottomPanel::bottom("error_bar_2")
// .default_height(26.0)
// .show(ctx, |ui| {
// ui.
// with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
// if ui
// .add(Button::new(RichText::new("Okay").size(20.0)))
// .clicked()
// {
// // frame.close();
// // ui.close_menu();
// }
// });
// });
});
}
}

View File

@@ -3,13 +3,11 @@ use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use std::time::SystemTime;
use egui::Vec2;
use log::error;
use rog_anime::{Animations, DeviceState};
use rog_aura::aura_detection::PowerZones;
use rog_aura::layouts::KeyLayout;
use rog_aura::usb::{AuraDevice, AuraPowerDev};
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, LedBrightness};
use rog_aura::usb::AuraPowerDev;
use rog_aura::{AuraEffect, AuraModeNum, LedBrightness};
use rog_platform::platform::{GpuMode, ThrottlePolicy};
use rog_profiles::fan_curve_set::CurveData;
use rog_profiles::FanCurvePU;
@@ -69,7 +67,7 @@ pub struct FanCurvesState {
pub show_graph: FanCurvePU,
pub curves: BTreeMap<ThrottlePolicy, Vec<CurveData>>,
pub available_fans: HashSet<FanCurvePU>,
pub drag_delta: Vec2,
// pub drag_delta: Vec2,
}
impl FanCurvesState {
@@ -102,7 +100,7 @@ impl FanCurvesState {
show_graph: FanCurvePU::CPU,
curves,
available_fans,
drag_delta: Vec2::default(),
// drag_delta: Vec2::default(),
})
}
}
@@ -112,9 +110,6 @@ pub struct AuraState {
pub current_mode: AuraModeNum,
pub modes: BTreeMap<AuraModeNum, AuraEffect>,
pub enabled: AuraPowerDev,
pub dev_type: AuraDevice,
pub supported_basic_zones: Vec<AuraZone>,
pub supported_power_zones: Vec<PowerZones>,
/// Brightness from 0-3
pub bright: LedBrightness,
pub wave_red: [u8; 22],
@@ -126,7 +121,10 @@ impl AuraState {
pub fn new(layout: &KeyLayout, dbus: &RogDbusClientBlocking<'_>) -> Result<Self> {
Ok(Self {
current_mode: if !layout.basic_modes().is_empty() {
dbus.proxies().aura().led_mode().unwrap_or_default()
dbg!();
let x = dbus.proxies().aura().led_mode().unwrap_or_default();
dbg!();
x
} else {
AuraModeNum::Static
},
@@ -137,18 +135,7 @@ impl AuraState {
BTreeMap::new()
},
enabled: dbus.proxies().aura().led_power().unwrap_or_default(),
supported_basic_zones: dbus
.proxies()
.aura()
.supported_basic_zones()
.unwrap_or_default(),
supported_power_zones: dbus
.proxies()
.aura()
.supported_power_zones()
.unwrap_or_default(),
dev_type: dbus.proxies().aura().device_type().unwrap_or_default(),
bright: dbus.proxies().aura().brightness().unwrap_or_default(),
bright: Default::default(),
wave_red: [0u8; 22],
wave_green: [0u8; 22],
wave_blue: [0u8; 22],
@@ -291,9 +278,9 @@ impl SystemState {
tray_enabled: bool,
run_in_bg: bool,
) -> Result<Self> {
dbg!();
let (asus_dbus, conn) = RogDbusClientBlocking::new()?;
let gfx_dbus = GfxProxyBlocking::new(&conn).expect("Couldn't connect to supergfxd");
dbg!();
let aura = AuraState::new(&keyboard_layout, &asus_dbus)
.map_err(|e| {
let e = format!("Could not get AuraState state: {e}");
@@ -301,6 +288,12 @@ impl SystemState {
})
.unwrap_or_default();
dbg!();
let gfx_dbus = GfxProxyBlocking::builder(&conn)
.destination(":org.supergfxctl.Daemon")?
.build()
.expect("Couldn't connect to supergfxd");
dbg!();
Ok(Self {
aura_creation: AuraCreation::new(layout_testing, keyboard_layout, keyboard_layouts),
enabled_notifications,
@@ -348,7 +341,9 @@ impl SystemState {
impl Default for SystemState {
fn default() -> Self {
let (asus_dbus, conn) = RogDbusClientBlocking::new().expect("Couldn't connect to asusd");
let gfx_dbus = GfxProxyBlocking::new(&conn).expect("Couldn't connect to supergfxd");
let gfx_dbus = GfxProxyBlocking::builder(&conn)
.build()
.expect("Couldn't connect to supergfxd");
Self {
aura_creation: AuraCreation {

View File

@@ -86,7 +86,7 @@ impl ROGTray {
e
})?;
let gfx_proxy = GfxProxyBlocking::new(&conn).map_err(|e| {
let gfx_proxy = GfxProxyBlocking::builder(&conn).build().map_err(|e| {
error!("ROGTray: {e}");
e
})?;

View File

@@ -98,7 +98,7 @@ macro_rules! recv_notif {
log::error!("zbus signal: {}: {e}", stringify!($signal));
e
}).unwrap();
let proxy = $proxy::new(&conn).await.map_err(|e| {
let proxy = $proxy::builder(&conn).build().await.map_err(|e| {
log::error!("zbus signal: {}: {e}", stringify!($signal));
e
}).unwrap();
@@ -446,7 +446,8 @@ pub fn start_notifications(
e
})
.unwrap();
let proxy = SuperProxy::new(&conn)
let proxy = SuperProxy::builder(&conn)
.build()
.await
.map_err(|e| {
error!("zbus signal: receive_notify_action: {e}");

View File

@@ -1,83 +0,0 @@
use egui::{RichText, Ui};
use rog_anime::usb::Brightness;
use crate::system_state::SystemState;
pub fn anime_power_group(states: &mut SystemState, ui: &mut Ui) {
ui.heading("AniMe Matrix Settings");
ui.label("Options are incomplete. Awake + Boot should work");
ui.horizontal_wrapped(|ui| {
ui.vertical(|ui| {
let h = 16.0;
ui.set_row_height(22.0);
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Display brightness").size(h));
});
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Display enabled").size(h));
});
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Animations enabled").size(h));
});
// ui.horizontal_wrapped(|ui| {
// ui.label(RichText::new("Sleep").size(h));
// });
});
ui.vertical(|ui| {
ui.set_row_height(22.0);
ui.horizontal_wrapped(|ui| {
let slider =
egui::Slider::new(&mut states.anime.display_brightness, 0..=3).step_by(1.0);
if ui.add(slider).drag_released() {
states
.asus_dbus
.proxies()
.anime()
.set_brightness(Brightness::from(states.anime.display_brightness))
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
});
ui.horizontal_wrapped(|ui| {
if ui
.checkbox(&mut states.anime.display_enabled, "Enable")
.changed()
{
states
.asus_dbus
.proxies()
.anime()
.set_enable_display(states.anime.display_enabled)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
});
ui.horizontal_wrapped(|ui| {
if ui
.checkbox(&mut states.anime.builtin_anims_enabled, "Enable")
.changed()
{
states
.asus_dbus
.proxies()
.anime()
.set_builtins_enabled(states.anime.builtin_anims_enabled)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
});
// ui.horizontal_wrapped(|ui| {
// if ui.checkbox(&mut states.anime.sleep, "Enable").changed() {
// changed = true;
// }
// });
});
});
}

View File

@@ -1,117 +0,0 @@
use egui::Ui;
use crate::config::Config;
use crate::system_state::SystemState;
pub fn app_settings(config: &mut Config, states: &mut SystemState, ui: &mut Ui) {
ui.heading("App Settings");
let mut enabled_notifications = if let Ok(lock) = states.enabled_notifications.lock() {
lock.clone()
} else {
Default::default()
};
ui.label("Application settings");
let app_changed = ui
.checkbox(
&mut config.enable_tray_icon,
"Enable Tray Icon (restart required)",
)
.clicked()
|| ui
.checkbox(&mut config.run_in_background, "Run in Background")
.clicked()
|| ui
.checkbox(&mut config.startup_in_background, "Startup Hidden")
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.all_enabled,
"Enable Notifications",
)
.clicked();
// if ui.button("Quit").clicked() {
// states.run_in_bg = false;
// }
ui.label("Notification settings");
let notif_changed = ui
.checkbox(
&mut enabled_notifications.receive_notify_gfx_status,
"Enable dGPU status notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_led_mode_data_changed,
"Enable LED mode change notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_dgpu_disable_changed,
"Enable dGPU disablement notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_egpu_enable_changed,
"Enable eGPU enablement notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_notify_mains_online,
"Enable mains (AC) power notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_charge_control_end_threshold_changed,
"Enable charge threshold notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_throttle_thermal_policy_changed,
"Enable profile change notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_panel_od_changed,
"Enable panel overdrive notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_mini_led_mode_changed,
"Enable MiniLED mode notification",
)
.clicked()
|| ui
.checkbox(
&mut enabled_notifications.receive_post_animation_sound_changed,
"Enable BIOS post sound notification",
)
.clicked();
if app_changed || notif_changed {
if let Ok(mut lock) = states.enabled_notifications.lock() {
// Replace inner content before save
*lock = enabled_notifications;
config
.save(&lock)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
states.tray_enabled = config.enable_tray_icon;
states.run_in_bg = config.run_in_background;
}
}
}

View File

@@ -1,237 +0,0 @@
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;
use egui::{RichText, Ui};
use rog_aura::layouts::KeyLayout;
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Speed};
use crate::system_state::SystemState;
pub fn aura_modes_group(states: &mut SystemState, freq: &mut Arc<AtomicU8>, ui: &mut Ui) {
let mut changed = false;
let mut selected = states.aura.current_mode;
let allowed = AuraEffect::allowed_parameters(selected);
let SystemState { aura_creation, .. } = states;
let has_keyzones = aura_creation
.keyboard_layout
.basic_zones()
.contains(&AuraZone::Key2);
let has_logo = aura_creation
.keyboard_layout
.basic_zones()
.contains(&AuraZone::Logo);
let has_lightbar = aura_creation
.keyboard_layout
.basic_zones()
.contains(&AuraZone::BarLeft)
|| aura_creation
.keyboard_layout
.basic_zones()
.contains(&AuraZone::BarRight);
if let Some(p) = aura_creation.layout_testing.as_ref() {
ui.heading(format!("{p:?}"));
} else {
ui.heading("Aura modes");
ui.label(
"Please note that this section is incomplete and the displayed effects won't match \
actual effect",
);
}
let mut item = |a: AuraModeNum, ui: &mut Ui| {
if ui
.selectable_value(&mut selected, a, format!("{:?}", a))
.clicked()
{
changed = true;
}
};
ui.horizontal_wrapped(|ui| {
for a in states.aura.modes.keys() {
item(*a, ui);
}
});
if let Some(effect) = states.aura.modes.get_mut(&selected) {
let mut zone_button = |a: AuraZone, ui: &mut Ui| {
ui.selectable_value(&mut effect.zone, a, format!("{:?}", a));
};
let mut speed_button = |a: Speed, ui: &mut Ui| -> bool {
if ui
.selectable_value(&mut effect.speed, a, format!("{:?}", a))
.clicked()
{
let val = match effect.speed {
Speed::Low => 6,
Speed::Med => 8,
Speed::High => 10,
};
freq.store(val, Ordering::SeqCst);
return true;
}
false
};
let mut dir_button = |a: rog_aura::Direction, ui: &mut Ui| -> bool {
ui.selectable_value(&mut effect.direction, a, format!("{:?}", a))
.clicked()
};
let mut c1: [u8; 3] = effect.colour1.into();
let mut c2: [u8; 3] = effect.colour2.into();
ui.separator();
ui.horizontal_wrapped(|ui| {
ui.vertical(|ui| {
let h = 16.0;
ui.set_row_height(22.0);
ui.add_enabled_ui(allowed.zone, |ui| {
if has_keyzones || has_lightbar || has_logo {
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Zone").size(h));
});
}
});
ui.add_enabled_ui(allowed.colour1, |ui| {
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Colour 1").size(h));
});
});
ui.add_enabled_ui(allowed.colour2, |ui| {
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Colour 2").size(h));
});
});
ui.add_enabled_ui(allowed.speed, |ui| {
ui.horizontal_wrapped(|ui| {
ui.set_enabled(allowed.speed);
ui.label(RichText::new("Speed").size(h));
});
});
ui.add_enabled_ui(allowed.direction, |ui| {
ui.horizontal_wrapped(|ui| {
ui.set_enabled(allowed.direction);
ui.label(RichText::new("Direction").size(h));
});
});
ui.set_enabled(true);
});
ui.vertical(|ui| {
ui.set_row_height(22.0);
ui.add_enabled_ui(allowed.zone, |ui| {
if has_keyzones || has_lightbar || has_logo {
ui.horizontal_wrapped(|ui| {
zone_button(AuraZone::None, ui);
if has_keyzones {
zone_button(AuraZone::Key1, ui);
zone_button(AuraZone::Key2, ui);
zone_button(AuraZone::Key3, ui);
zone_button(AuraZone::Key4, ui);
}
if has_logo {
zone_button(AuraZone::Logo, ui);
}
if has_lightbar {
zone_button(AuraZone::BarLeft, ui);
zone_button(AuraZone::BarRight, ui);
}
});
}
});
ui.add_enabled_ui(allowed.colour1, |ui| {
if egui::color_picker::color_edit_button_srgb(ui, &mut c1).changed() {
changed = true;
}
});
ui.add_enabled_ui(allowed.colour2, |ui| {
if egui::color_picker::color_edit_button_srgb(ui, &mut c2).changed() {
changed = true;
}
});
ui.add_enabled_ui(allowed.speed, |ui| {
ui.horizontal_wrapped(|ui| {
if speed_button(Speed::Low, ui)
|| speed_button(Speed::Med, ui)
|| speed_button(Speed::High, ui)
{
changed = true;
}
});
});
ui.add_enabled_ui(allowed.direction, |ui| {
ui.horizontal_wrapped(|ui| {
if dir_button(rog_aura::Direction::Left, ui)
|| dir_button(rog_aura::Direction::Down, ui)
|| dir_button(rog_aura::Direction::Right, ui)
|| dir_button(rog_aura::Direction::Up, ui)
{
changed = true;
}
});
});
});
});
effect.colour1 = Colour::from(&c1);
effect.colour2 = Colour::from(&c2);
}
ui.separator();
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
// if ui.add(egui::Button::new("Cancel")).clicked() {
// match AuraState::new(&aura_creation.keyboard_layout, &states.asus_dbus) {
// Ok(a) => states.aura.modes = a.modes,
// Err(e) => states.error = Some(e.to_string()),
// }
// }
// if ui.add(egui::Button::new("Apply")).clicked() {
// changed = true;
// }
if aura_creation.layout_testing.is_some() {
if ui.add(egui::Button::new("Next layout")).clicked() {
if aura_creation.keyboard_layout_index < aura_creation.keyboard_layouts.len() - 1 {
aura_creation.keyboard_layout_index += 1;
}
aura_creation.layout_testing = Some(
aura_creation.keyboard_layouts[aura_creation.keyboard_layout_index].clone(),
);
aura_creation.keyboard_layout =
KeyLayout::from_file(aura_creation.layout_testing.as_ref().unwrap().as_path())
.unwrap();
}
if ui.add(egui::Button::new("Prev layout")).clicked() {
if aura_creation.keyboard_layout_index > 0 {
aura_creation.keyboard_layout_index -= 1;
}
aura_creation.layout_testing = Some(
aura_creation.keyboard_layouts[aura_creation.keyboard_layout_index].clone(),
);
aura_creation.keyboard_layout =
KeyLayout::from_file(aura_creation.layout_testing.as_ref().unwrap().as_path())
.unwrap();
}
}
});
if changed {
states.aura.current_mode = selected;
states
.asus_dbus
.proxies()
.aura()
.set_led_mode_data(states.aura.modes.get(&selected).unwrap().clone())
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
}

View File

@@ -1,266 +0,0 @@
use egui::{RichText, Ui};
use rog_aura::power::{AuraPower, KbAuraPowerState};
use rog_aura::usb::{AuraDevRog1, AuraDevTuf, AuraDevice, AuraPowerDev};
use crate::system_state::SystemState;
pub fn aura_power_group(states: &mut SystemState, ui: &mut Ui) {
ui.heading("Keyboard LED power settings");
if states.aura.dev_type.is_old_style() || states.aura.dev_type.is_tuf_style() {
aura_power1(states, ui);
} else if states.aura.dev_type.is_new_style() {
aura_power2(states, ui);
}
}
fn aura_power1(states: &mut SystemState, ui: &mut Ui) {
let enabled_states = &mut states.aura.enabled;
let mut boot = enabled_states.old_rog.contains(&AuraDevRog1::Boot);
let mut sleep = enabled_states.old_rog.contains(&AuraDevRog1::Sleep);
let mut keyboard = enabled_states.old_rog.contains(&AuraDevRog1::Keyboard);
let mut lightbar = enabled_states.old_rog.contains(&AuraDevRog1::Lightbar);
if states.aura.dev_type == AuraDevice::Tuf {
boot = enabled_states.tuf.contains(&AuraDevTuf::Boot);
sleep = enabled_states.tuf.contains(&AuraDevTuf::Sleep);
keyboard = enabled_states.tuf.contains(&AuraDevTuf::Awake);
}
let mut changed = false;
ui.horizontal_wrapped(|ui| {
ui.vertical(|ui| {
let h = 16.0;
ui.set_row_height(22.0);
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Boot").size(h));
});
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Awake").size(h));
});
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new("Sleep").size(h));
});
// if supported.keyboard_led.brightness_set {
// ui.horizontal_wrapped(|ui| {
// ui.label(RichText::new("Brightness").size(h));
// });
// }
});
ui.vertical(|ui| {
ui.set_row_height(22.0);
ui.horizontal_wrapped(|ui| {
if ui.checkbox(&mut boot, "Enable").changed() {
changed = true;
}
});
ui.horizontal_wrapped(|ui| {
if ui.toggle_value(&mut keyboard, "Keyboard").changed() {
changed = true;
}
if !states.aura.supported_basic_zones.is_empty()
&& ui.toggle_value(&mut lightbar, "Lightbar").changed()
{
changed = true;
}
});
ui.horizontal_wrapped(|ui| {
if ui.checkbox(&mut sleep, "Enable").changed() {
changed = true;
}
});
// We currently don't have a watch for system changes here
// if supported.keyboard_led.brightness_set {
// if ui
// .add(egui::Slider::new(
// &mut states.aura.bright,
// 0..=3,
// ))
// .changed()
// {
// let bright = LedBrightness::from(states.aura.bright as
// u32); dbus.proxies()
// .led()
// .set_brightness(bright)
// .map_err(|err| {
// states.error = Some(err.to_string());
// })
// .ok();
// }
// }
});
});
if changed {
if states.aura.dev_type == AuraDevice::Tuf {
let mut enabled = Vec::new();
let mut disabled = Vec::new();
let mut modify_tuf = |b: bool, a: AuraDevTuf| {
if b {
enabled.push(a);
if !enabled_states.tuf.contains(&a) {
enabled_states.tuf.push(a);
}
} else {
disabled.push(a);
// This would be so much better as a hashset
if enabled_states.tuf.contains(&a) {
let mut idx = 0;
for (i, n) in enabled_states.tuf.iter().enumerate() {
if *n == a {
idx = i;
break;
}
}
enabled_states.tuf.remove(idx);
}
}
};
modify_tuf(boot, AuraDevTuf::Boot);
modify_tuf(sleep, AuraDevTuf::Sleep);
modify_tuf(keyboard, AuraDevTuf::Awake);
let mut send = |enable: bool, data: Vec<AuraDevTuf>| {
let options = AuraPowerDev {
tuf: data,
..Default::default()
};
// build data to send
states
.asus_dbus
.proxies()
.aura()
.set_led_power((options, enable))
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
};
send(true, enabled);
send(false, disabled);
} else {
let mut enabled = Vec::new();
let mut disabled = Vec::new();
let mut modify_x1866 = |b: bool, a: AuraDevRog1| {
if b {
enabled.push(a);
if !enabled_states.old_rog.contains(&a) {
enabled_states.old_rog.push(a);
}
} else {
disabled.push(a);
// This would be so much better as a hashset
if enabled_states.old_rog.contains(&a) {
let mut idx = 0;
for (i, n) in enabled_states.old_rog.iter().enumerate() {
if *n == a {
idx = i;
break;
}
}
enabled_states.old_rog.remove(idx);
}
}
};
modify_x1866(boot, AuraDevRog1::Boot);
modify_x1866(sleep, AuraDevRog1::Sleep);
modify_x1866(keyboard, AuraDevRog1::Keyboard);
if !states.aura.supported_basic_zones.is_empty() {
modify_x1866(lightbar, AuraDevRog1::Lightbar);
}
let mut send = |enable: bool, data: Vec<AuraDevRog1>| {
let options = AuraPowerDev {
old_rog: data,
..Default::default()
};
// build data to send
states
.asus_dbus
.proxies()
.aura()
.set_led_power((options, enable))
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
};
send(true, enabled);
send(false, disabled);
}
}
}
fn aura_power2(states: &mut SystemState, ui: &mut Ui) {
let AuraPower {
keyboard,
logo,
lightbar,
lid,
rear_glow,
} = &mut states.aura.enabled.rog;
const LABELS: [&str; 4] = ["Boot", "Awake", "Sleep", "Shutdown"];
let mut changed = false;
let mut item = |power: &mut KbAuraPowerState, ui: &mut Ui| {
ui.vertical(|ui| {
if states.aura.supported_power_zones.contains(&power.zone) {
ui.horizontal_wrapped(|ui| {
ui.label(RichText::new(format!("{:?}", power.zone)).size(14.0));
});
if ui.checkbox(&mut power.boot, LABELS[0]).changed() {
changed = true;
}
if ui.checkbox(&mut power.awake, LABELS[1]).changed() {
changed = true;
}
if ui.checkbox(&mut power.sleep, LABELS[2]).changed() {
changed = true;
}
if ui.checkbox(&mut power.shutdown, LABELS[3]).changed() {
changed = true;
}
}
});
};
ui.horizontal_wrapped(|ui| {
item(lid, ui);
item(logo, ui);
item(keyboard, ui);
item(lightbar, ui);
item(rear_glow, ui);
});
if changed {
let mut send = |enable: bool, data: AuraPower| {
let options = AuraPowerDev {
rog: data,
..Default::default()
};
// build data to send
states
.asus_dbus
.proxies()
.aura()
.set_led_power((options, enable))
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
};
send(
true,
AuraPower {
keyboard: *keyboard,
logo: *logo,
lightbar: *lightbar,
lid: *lid,
rear_glow: *rear_glow,
},
);
}
}

View File

@@ -1,208 +0,0 @@
use egui::plot::{Line, Plot, Points};
use egui::Ui;
use rog_platform::platform::ThrottlePolicy;
use rog_profiles::fan_curve_set::CurveData;
use rog_profiles::FanCurvePU;
use crate::system_state::FanCurvesState;
use crate::RogDbusClientBlocking;
pub fn fan_graphs(
curves: &mut FanCurvesState,
dbus: &RogDbusClientBlocking<'_>,
do_error: &mut Option<String>,
ui: &mut Ui,
) {
if curves.available_fans.is_empty() {
return; // TODO:
}
ui.separator();
let mut item = |profile: ThrottlePolicy, ui: &mut Ui| {
ui.group(|ui| {
if ui
.selectable_value(&mut curves.show_curve, profile, format!("{profile:?}"))
.clicked()
{
dbus.proxies()
.platform()
.set_throttle_thermal_policy(profile)
.ok();
}
ui.add_enabled_ui(curves.show_curve == profile, |ui| {
if curves.available_fans.contains(&FanCurvePU::CPU) {
ui.selectable_value(
&mut curves.show_graph,
FanCurvePU::CPU,
format!("{:?}", FanCurvePU::CPU),
);
}
if curves.available_fans.contains(&FanCurvePU::GPU) {
ui.selectable_value(
&mut curves.show_graph,
FanCurvePU::GPU,
format!("{:?}", FanCurvePU::GPU),
);
}
if curves.available_fans.contains(&FanCurvePU::MID) {
ui.selectable_value(
&mut curves.show_graph,
FanCurvePU::MID,
format!("{:?}", FanCurvePU::MID),
);
}
});
});
};
ui.horizontal_wrapped(|ui| {
for a in &curves.curves {
item(*a.0, ui);
}
});
let curve = curves.curves.get_mut(&curves.show_curve).unwrap();
let mut data = &mut CurveData::default();
for c in curve {
if c.fan == curves.show_graph {
data = c;
break;
}
}
let mut points: Vec<[f64; 2]> = data
.temp
.iter()
.enumerate()
.map(|(idx, x)| {
let x = *x as f64;
let y = ((data.pwm[idx] as u32) * 100 / 255) as f64;
[x, y]
})
.collect();
for i in 0..points.len() - 1 {
if i > 0 && i < points.len() - 1 {
if points[i][0] < points[i - 1][0] {
points[i][0] = points[i - 1][0] + 1.0;
data.temp[i] = points[i - 1][0] as u8;
}
if points[i][0] >= points[i + 1][0] {
points[i + 1][0] = points[i][0] + 1.0;
data.temp[i + 1] = points[i][0] as u8;
}
if points[i][1] < points[i - 1][1] {
points[i][1] = points[i - 1][1] + 1.0;
data.pwm[i] = (points[i - 1][1] * 255.0 / 100.0 + 1.0).floor() as u8;
}
if points[i][1] >= points[i + 1][1] {
points[i + 1][1] = points[i][1] + 1.0;
data.pwm[i + 1] = (points[i][1] * 255.0 / 100.0 + 1.0).floor() as u8;
}
}
}
let line = Line::new(points.clone()).width(2.0);
let points = Points::new(points).radius(3.0);
Plot::new("fan_curves")
.view_aspect(1.666)
// .center_x_axis(true)
// .center_y_axis(true)
.include_x(0.0)
.include_x(104.0)
.include_y(0.0)
.include_y(106.0)
.allow_scroll(false)
.allow_drag(false)
.allow_boxed_zoom(false)
// .x_axis_formatter(|d, _r| format!("{}", d))
// .y_axis_formatter(|d, _r| format!("{:.*}%", 1, d))
.label_formatter(|name, value| {
if !name.is_empty() {
format!("{}: {:.*}%", name, 1, value.y)
} else {
format!("Temp {}c\nFan {:.*}%", value.x as u8, 1, value.y)
}
})
.show(ui, |plot_ui| {
if plot_ui.plot_hovered() {
let mut idx = 0;
if let Some(point) = plot_ui.pointer_coordinate() {
let mut x: i32 = point.x as i32;
for (i, n) in data.temp.iter().enumerate() {
let tmp = x.min((point.x as i32 - *n as i32).abs());
if tmp < x {
x = tmp;
idx = i;
}
}
if plot_ui.plot_clicked() {
data.temp[idx] = point.x as u8;
data.pwm[idx] = (point.y * 255.0 / 100.0) as u8;
} else {
let drag = plot_ui.pointer_coordinate_drag_delta();
if drag.length_sq() != 0.0 {
data.temp[idx] = (point.x as f32 + drag.x) as u8;
data.pwm[idx] = ((point.y as f32 + drag.y) * 255.0 / 100.0) as u8;
}
}
}
}
plot_ui.line(line);
plot_ui.points(points);
});
let mut set = false;
let mut clear = false;
let mut reset = false;
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
set = ui.add(egui::Button::new("Apply Profile")).clicked();
clear = ui.add(egui::Button::new("Clear Profile Changes")).clicked();
reset = ui.add(egui::Button::new("Factory Reset Profile")).clicked();
});
if set {
dbus.proxies()
.fan_curves()
.set_fan_curve(curves.show_curve, data.clone())
.map_err(|err| {
*do_error = Some(err.to_string());
})
.ok();
}
if clear {
if let Ok(curve) = dbus
.proxies()
.fan_curves()
.fan_curve_data(curves.show_curve)
.map_err(|err| {
*do_error = Some(err.to_string());
})
{
if let Some(value) = curves.curves.get_mut(&curves.show_curve) {
*value = curve;
}
}
}
if reset {
dbus.proxies()
.fan_curves()
.reset_profile_curves(curves.show_curve)
.map_err(|err| {
*do_error = Some(err.to_string());
})
.ok();
match FanCurvesState::new(dbus) {
Ok(f) => *curves = f,
Err(e) => *do_error = Some(e.to_string()),
}
}
}

View File

@@ -1,220 +0,0 @@
use egui::{Color32, Pos2};
use rog_aura::advanced::LedCode;
use rog_aura::layouts::{KeyLayout, KeyShape};
use rog_aura::{AdvancedAuraType, AuraModeNum};
use crate::system_state::AuraState;
const SCALE: f32 = 2.0;
// TODO:
// - Multizone: draw regions? While iterating keys check if located in one of
// the 4 regions and mark
// - Tab for advanced effects
// - Keys need to select colour themselves
pub fn keyboard(
ui: &mut egui::Ui,
keyboard_layout: &KeyLayout,
states: &mut AuraState,
colour: Color32,
) {
let (keyboard_is_multizoned, keyboard_width, keyboard_is_per_key) =
match keyboard_layout.advanced_type() {
AdvancedAuraType::PerKey => (false, 0.0, true),
AdvancedAuraType::None => (false, keyboard_layout.max_width(), false),
AdvancedAuraType::Zoned(zones) => {
let width = if let Some(row) = keyboard_layout.rows_ref().get(2) {
row.width()
} else {
0.0
};
(!zones.contains(&LedCode::SingleZone), width, false)
}
};
let mut start_pos = None;
let y = ui.spacing().interact_size.y;
let this_size = ui.available_size();
let keys_width = keyboard_layout.max_width() * SCALE * y;
let keys_height = keyboard_layout.max_height() * SCALE * y;
let keyboard_height = keyboard_layout.keyboard_height() * SCALE;
let x_start = (this_size.x - keys_width) / SCALE;
let y_start = (this_size.y - keys_height) / SCALE;
// Initial colour states
let mut input_colour = colour;
let mut key_colour = colour;
if states.current_mode == AuraModeNum::Rainbow && !keyboard_is_per_key {
key_colour = Color32::from_rgb(
(states.wave_red[0] as u32 * 255 / 100) as u8,
(states.wave_green[0] as u32 * 255 / 100) as u8,
(states.wave_blue[0] as u32 * 255 / 100) as u8,
);
}
ui.spacing_mut().item_spacing = egui::vec2(0.0, 0.0);
blank(ui, 0.0, y_start / y);
for row in keyboard_layout.rows() {
ui.horizontal_top(|ui| {
blank(ui, x_start / y, 0.0);
for (i, key) in row.row().enumerate() {
// For per-key rainbow which cascades across
if states.current_mode == AuraModeNum::Rainbow && keyboard_is_per_key
|| key.0.is_lightbar_zone()
{
key_colour = Color32::from_rgb(
(states.wave_red[i] as u32 * 255 / 100) as u8,
(states.wave_green[i] as u32 * 255 / 100) as u8,
(states.wave_blue[i] as u32 * 255 / 100) as u8,
);
}
if (keyboard_is_multizoned && !key.0.is_lightbar_zone())
&& states.current_mode == AuraModeNum::Rainbow
{
input_colour = key_colour;
key_colour = Color32::TRANSPARENT;
}
let label = <&str>::from(key.0);
let mut shape = key.1.clone();
shape.scale(SCALE);
match shape {
KeyShape::Led {
width,
height,
pad_left,
pad_right,
pad_top,
pad_bottom,
} => {
let (pos, response) = key_shape(
ui, key_colour, width, height, pad_left, pad_right, pad_top, pad_bottom,
);
if start_pos.is_none() {
start_pos = Some(pos);
} else if let Some(old_pos) = start_pos.as_mut() {
if !key.0.is_lightbar_zone() {
if pos.x < old_pos.x {
old_pos.x = pos.x;
}
if pos.y < old_pos.y {
old_pos.y = pos.y;
}
}
}
if response.on_hover_text(label).clicked() && keyboard_is_per_key {
// TODO: set an effect on the LedCode
}
}
KeyShape::Blank { width, height } => {
blank(ui, width, height);
}
}
}
});
}
if keyboard_is_multizoned {
let zone_width = keyboard_width * SCALE / 4.0 - 0.1;
for n in 0..4 {
if states.current_mode == AuraModeNum::Rainbow {
input_colour = Color32::from_rgba_unmultiplied(
(states.wave_red[n] as u32 * 255 / 100) as u8,
(states.wave_green[n] as u32 * 255 / 100) as u8,
(states.wave_blue[n] as u32 * 255 / 100) as u8,
70,
);
}
if let Some(mut pos) = start_pos {
pos.x += n as f32 * zone_width * y;
let response = zone_shape(ui, input_colour, pos, zone_width, keyboard_height);
let label = format!("Zone {}", 1 + n);
if response.on_hover_text(label).clicked() {
// TODO: set an effect on the zone
}
}
}
}
}
#[allow(clippy::too_many_arguments)]
fn key_shape(
ui: &mut egui::Ui,
colour: Color32,
width: f32,
height: f32,
pad_left: f32,
pad_right: f32,
pad_top: f32,
pad_bottom: f32,
) -> (egui::Pos2, egui::Response) {
// First, get some space
let y = ui.spacing().interact_size.y;
let desired_size = y * egui::vec2(width + pad_left + pad_right, height + pad_top + pad_bottom);
let (mut rect, mut response) = ui.allocate_exact_size(desired_size, egui::Sense::click());
// rect = rect.shrink(3.0);
if response.clicked() {
response.mark_changed();
}
response.widget_info(|| {
egui::WidgetInfo::selected(egui::WidgetType::Checkbox, response.clicked(), "")
});
if ui.is_rect_visible(rect) {
// Now set the actual visible rect
let visuals = ui.style().interact_selectable(&response, true);
let size = y * egui::vec2(width, height);
rect.set_width(size.x);
rect.set_height(size.y);
let center = Pos2::new(
rect.center().x + pad_left * y,
rect.center().y + pad_top * y,
);
rect.set_center(center);
// let rect = rect.expand(visuals.expansion);
ui.painter().rect(rect, 0.1, colour, visuals.fg_stroke);
}
(rect.left_top(), response)
}
#[allow(clippy::too_many_arguments)]
fn zone_shape(
ui: &mut egui::Ui,
mut colour: Color32,
pos: Pos2,
width: f32,
height: f32,
) -> egui::Response {
// First, get some space
let y = ui.spacing().interact_size.y;
let desired_size = y * egui::vec2(width, height);
let rect = egui::Rect::from_min_size(pos, desired_size);
let mut response = ui.allocate_rect(rect, egui::Sense::click());
// rect = rect.shrink(3.0);
if response.clicked() {
response.mark_changed();
}
response.widget_info(|| {
egui::WidgetInfo::selected(egui::WidgetType::Checkbox, response.clicked(), "")
});
if ui.is_rect_visible(rect) {
// Now set the actual visible rect
let visuals = ui.style().interact_selectable(&response, true);
// let rect = rect.expand(visuals.expansion);
colour[3] = 20;
ui.painter().rect(rect, 0.1, colour, visuals.fg_stroke);
}
response
}
fn blank(ui: &mut egui::Ui, ux: f32, uy: f32) {
let desired_size = ui.spacing().interact_size.y * egui::vec2(ux, uy);
ui.allocate_exact_size(desired_size, egui::Sense::click());
}

View File

@@ -1,17 +0,0 @@
mod anime_power;
mod app_settings;
mod aura_modes;
mod aura_power;
mod fan_graph;
mod keyboard_layout;
mod rog_bios;
mod side_panel;
mod top_bar;
pub use anime_power::*;
pub use app_settings::*;
pub use aura_modes::*;
pub use aura_power::*;
pub use fan_graph::*;
pub use keyboard_layout::*;
pub use rog_bios::*;

View File

@@ -1,153 +0,0 @@
use egui::Ui;
use rog_platform::platform::{GpuMode, ThrottlePolicy};
use crate::system_state::SystemState;
pub fn platform_profile(states: &mut SystemState, ui: &mut Ui) {
if let Some(mut throttle) = states.bios.throttle {
ui.heading("Platform profile");
let mut item = |p: ThrottlePolicy, ui: &mut Ui| {
if ui
.selectable_value(&mut throttle, p, format!("{p:?}"))
.clicked()
{
states
.asus_dbus
.proxies()
.platform()
.set_throttle_thermal_policy(throttle)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
};
ui.horizontal_wrapped(|ui| {
for a in ThrottlePolicy::list() {
item(a, ui);
}
});
}
}
pub fn rog_bios_group(states: &mut SystemState, ui: &mut Ui) {
ui.heading("Bios options");
if let Some(mut limit) = states.bios.charge_limit {
let slider = egui::Slider::new(&mut limit, 20..=100)
.text("Charging limit")
.step_by(1.0);
if ui.add(slider).drag_released() {
states
.asus_dbus
.proxies()
.platform()
.set_charge_control_end_threshold(limit)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
}
if let Some(mut sound) = states.bios.post_sound {
if ui
.add(egui::Checkbox::new(&mut sound, "POST sound"))
.changed()
{
states
.asus_dbus
.proxies()
.platform()
.set_post_animation_sound(sound)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
}
if let Some(mut overdrive) = states.bios.panel_overdrive {
if ui
.add(egui::Checkbox::new(&mut overdrive, "Panel overdrive"))
.changed()
{
states
.asus_dbus
.proxies()
.platform()
.set_panel_od(overdrive)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
}
if let Some(mut mini_led_mode) = states.bios.mini_led_mode {
if ui
.add(egui::Checkbox::new(&mut mini_led_mode, "MiniLED backlight"))
.changed()
{
states
.asus_dbus
.proxies()
.platform()
.set_mini_led_mode(mini_led_mode)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
}
if let Some(mut gpu_mux_mode) = states.bios.gpu_mux_mode {
let mut changed = false;
let mut reboot_required = false;
if let Ok(mode) = states.asus_dbus.proxies().platform().gpu_mux_mode() {
reboot_required = GpuMode::from(mode) != gpu_mux_mode;
}
ui.group(|ui| {
ui.vertical(|ui| {
ui.horizontal_wrapped(|ui| ui.label("GPU MUX mode"));
ui.horizontal_wrapped(|ui| ui.label("NOTE: Value does not change until rebooted"));
ui.horizontal_wrapped(|ui| {
changed = ui
.selectable_value(
&mut gpu_mux_mode,
GpuMode::Discrete,
"Dedicated (Ultimate)",
)
.clicked()
|| ui
.selectable_value(
&mut gpu_mux_mode,
GpuMode::Optimus,
"Optimus (Hybrid)",
)
.clicked();
});
if reboot_required {
ui.horizontal_wrapped(|ui| ui.heading("REBOOT REQUIRED"));
}
});
});
if changed {
states
.asus_dbus
.proxies()
.platform()
.set_gpu_mux_mode(gpu_mux_mode)
.map_err(|err| {
states.error = Some(err.to_string());
})
.ok();
}
}
}

View File

@@ -1,72 +0,0 @@
use crate::{Page, RogApp};
impl RogApp {
pub fn side_panel(&mut self, ctx: &eframe::egui::Context) {
egui::SidePanel::left("side_panel")
.resizable(false)
.default_width(60.0) // TODO: set size to match icon buttons when done
.show(ctx, |ui| {
let Self { page, .. } = self;
ui.heading("Functions");
ui.separator();
if ui
.selectable_value(page, Page::System, "System Settings")
.clicked()
{
*page = Page::System;
}
if self.supported_interfaces.contains(&"FanCurves".to_owned()) {
ui.separator();
if ui
.selectable_value(page, Page::FanCurves, "Fan Curves")
.clicked()
{
*page = Page::FanCurves;
}
}
if self.supported_interfaces.contains(&"Aura".to_owned()) {
ui.separator();
if ui
.selectable_value(page, Page::AuraEffects, "Keyboard Aura")
.clicked()
{
*page = Page::AuraEffects;
}
}
// TODO: Anime page is not complete
if self.supported_interfaces.contains(&"Anime".to_owned()) {
ui.separator();
if ui
.selectable_value(page, Page::AnimeMatrix, "AniMe Matrix")
.clicked()
{
*page = Page::AnimeMatrix;
}
}
ui.separator();
if ui
.selectable_value(page, Page::AppSettings, "App Settings")
.clicked()
{
*page = Page::AppSettings;
}
ui.with_layout(egui::Layout::bottom_up(egui::Align::LEFT), |ui| {
ui.horizontal(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
ui.label("Source code ");
ui.hyperlink_to(
"rog-gui.",
"https://gitlab.com/asus-linux/asusctl/-/tree/main/rog-control-center",
);
});
});
});
}
}

View File

@@ -1,77 +0,0 @@
use egui::{vec2, Align2, Button, FontId, Id, Rect, RichText, Sense, Vec2};
use crate::{RogApp, VERSION};
impl RogApp {
pub fn top_bar(&mut self, ctx: &eframe::egui::Context, frame: &mut eframe::Frame) {
egui::TopBottomPanel::top("top_panel").show(ctx, |ui| {
// The top panel is often a good place for a menu bar:
egui::menu::bar(ui, |ui| {
ui.horizontal(|ui| {
self.dark_light_mode_buttons(ui);
egui::warn_if_debug_build(ui);
});
// Drag area
let text_color = ctx.style().visuals.text_color();
let mut titlebar_rect = ui.available_rect_before_wrap();
titlebar_rect.max.x -= titlebar_rect.height();
if ui
.interact(titlebar_rect, Id::new("title_bar"), Sense::drag())
.drag_started()
{
frame.drag_window();
}
let height = titlebar_rect.height();
// Paint the title:
ui.painter().text(
titlebar_rect.right_top() + vec2(0.0, height / 2.0),
Align2::RIGHT_CENTER,
format!("v{}", VERSION),
FontId::proportional(height - 2.0),
text_color,
);
// Add the close button:
let close_response = ui.put(
Rect::from_min_size(titlebar_rect.right_top(), Vec2::splat(height)),
Button::new(RichText::new("").size(height - 4.0)).frame(false),
);
if close_response.clicked() {
frame.close();
}
});
});
}
fn dark_light_mode_buttons(&mut self, ui: &mut egui::Ui) {
let load_from_cfg = self.config.dark_mode != ui.ctx().style().visuals.dark_mode;
if ui
.add(egui::SelectableLabel::new(
!self.config.dark_mode,
"☀ Light",
))
.clicked()
|| (load_from_cfg && !self.config.dark_mode)
{
ui.ctx().set_visuals(egui::Visuals::light());
}
if ui
.add(egui::SelectableLabel::new(self.config.dark_mode, "🌙 Dark"))
.clicked()
|| (load_from_cfg && self.config.dark_mode)
{
ui.ctx().set_visuals(egui::Visuals::dark());
}
let applied_dark_mode = ui.ctx().style().visuals.dark_mode;
if self.config.dark_mode != applied_dark_mode {
self.config.dark_mode = applied_dark_mode;
let tmp = self.config.enabled_notifications.clone();
self.config.save(&tmp).ok();
}
}
}