Compare commits

..

14 Commits

Author SHA1 Message Date
rforced
9cde2f83cf Merge branch 'fix-z13-2025-1' into 'devel'
Fixes for Asus z13 2025

See merge request asus-linux/asusctl!245
2026-01-23 14:47:44 -05:00
Denis Benato
2ea2cec172 Merge branch 'rogcc_ui_update' into 'devel'
ROGCC UI update

See merge request asus-linux/asusctl!250
2026-01-23 19:46:16 +00:00
Mykola Shevchenko
269041a7c6 ROGCC UI update 2026-01-23 19:46:15 +00:00
Denis Benato
6e83884c0a feat: GUI rework 2026-01-19 02:20:53 +01:00
Denis Benato
7edb77b41f fix: make the linter happy again 2026-01-18 23:43:22 +01:00
Denis Benato
737ffa522c chore: update CHANGELOG.md 2026-01-18 23:41:26 +01:00
Denis Benato
0311cfb1f9 fix: improve handling of different attribute types 2026-01-18 23:38:45 +01:00
Denis Benato
b0ee27fb74 Merge branch 'rogcc_toast_look_update' into 'devel'
rog-control-center toast message update

See merge request asus-linux/asusctl!248
2026-01-18 22:15:02 +00:00
Mykola Shevchenko
d4eca0c93e feat: improve toast message for rogcc 2026-01-18 22:15:02 +00:00
Josh Dariano
f471f340d4 Fix fan controls on z13 2026-01-16 16:37:15 -05:00
Josh Dariano
8095ac34ed Fix formatting 2026-01-16 15:48:02 -05:00
Josh Dariano
9d629b62ca Fix aura backlight for z13 2026-01-16 15:33:30 -05:00
Josh Dariano
5282c56f59 Merge remote-tracking branch 'rforced/fix-z13-2025' 2026-01-16 14:13:45 -05:00
Josh Dariano
0d2cd4eb10 Fix keyboard light 2026-01-16 13:57:35 -05:00
25 changed files with 651 additions and 428 deletions

View File

@@ -8,6 +8,9 @@ indent_style = space
trim_trailing_whitespace = true
insert_final_newline = true
[*.slint]
indent_size = 4
[*.md]
trim_trailing_whitespace = false

View File

@@ -1,5 +1,11 @@
# Changelog
## [6.3.2]
### Changes
- Improve the notification area, @shevchenko0013 strikes again!
- Improve firmware attributes handling
## [6.3.1]
### Changes

View File

@@ -2,7 +2,9 @@ use std::sync::Arc;
use config_traits::StdConfig;
use log::{debug, error, info, warn};
use rog_platform::asus_armoury::{AttrValue, Attribute, FirmwareAttribute, FirmwareAttributes};
use rog_platform::asus_armoury::{
AttrValue, Attribute, FirmwareAttribute, FirmwareAttributeType, FirmwareAttributes,
};
use rog_platform::platform::{PlatformProfile, RogPlatform};
use rog_platform::power::AsusPower;
use serde::{Deserialize, Serialize};
@@ -168,82 +170,64 @@ impl ArmouryAttributeRegistry {
impl crate::Reloadable for AsusArmouryAttribute {
async fn reload(&mut self) -> Result<(), RogError> {
info!("Reloading {}", self.attr.name());
let name: FirmwareAttribute = self.attr.name().into();
let attribute: FirmwareAttribute = self.attr.name().into();
let name = self.attr.name();
// Treat dGPU attributes the same as PPT attributes for power-profile
// behaviour so they follow AC/DC tuning groups.
if name.is_ppt() || name.is_dgpu() {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
.unwrap_or_default()
== 1;
let apply_value = {
let config = self.config.lock().await;
config
.select_tunings_ref(power_plugged, profile)
.and_then(|tuning| {
if tuning.enabled {
tuning.group.get(&self.name()).copied()
} else {
None
}
let config = self.config.lock().await;
let apply_value = match attribute.property_type() {
FirmwareAttributeType::Ppt => {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
};
.unwrap_or_default()
== 1;
if let Some(tune) = apply_value {
self.attr
.set_current_value(&AttrValue::Integer(tune))
.map_err(|e| {
error!("Could not set {} value: {e:?}", self.attr.name());
self.attr.base_path_exists();
e
})?;
info!(
"Restored PPT armoury setting {} to {:?}",
self.attr.name(),
tune
);
} else {
info!("Ignored restoring PPT armoury setting {} as tuning group is disabled or no saved value", self.attr.name());
let apply_value = {
config.select_tunings_ref(power_plugged, profile).and_then(
|tuning| match tuning.enabled {
true => tuning.group.get(&self.name()).copied(),
false => None,
},
)
};
apply_value.map_or(AttrValue::None, AttrValue::Integer)
}
} else {
// Handle non-PPT attributes (boolean and other settings)
if let Some(saved_value) = self.config.lock().await.armoury_settings.get(&name) {
self.attr
.set_current_value(&AttrValue::Integer(*saved_value))
.map_err(|e| {
error!(
"Error restoring armoury setting {}: {e:?}",
self.attr.name()
);
self.attr.base_path_exists();
e
})?;
info!(
"Restored armoury setting {} to {:?}",
self.attr.name(),
saved_value
);
} else {
info!(
"No saved armoury setting for {}: skipping restore",
self.attr.name()
);
FirmwareAttributeType::Gpu => {
info!("Reload called on GPU attribute {name}: doing nothing");
AttrValue::None
}
}
_ => {
info!("Reload called on firmware attribute {name}");
match config.armoury_settings.get(&attribute) {
Some(saved_value) => AttrValue::Integer(*saved_value),
None => AttrValue::None,
}
}
};
self.attr.set_current_value(&apply_value).map_err(|e| {
error!("Could not set {} value: {e:?}", self.attr.name());
self.attr.base_path_exists();
e
})?;
info!(
"Restored asus-armoury setting {} to {:?}",
self.attr.name(),
apply_value
);
Ok(())
}
}
/// If return is `-1` on a property then there is avilable value for that
/// If return is `-1` on a property then there is available value for that
/// property
#[interface(name = "xyz.ljones.AsusArmoury")]
impl AsusArmouryAttribute {
@@ -293,7 +277,7 @@ impl AsusArmouryAttribute {
async fn restore_default(&self) -> fdo::Result<()> {
self.attr.restore_default()?;
if self.name().is_ppt() || self.name().is_dgpu() {
if self.name().property_type() == FirmwareAttributeType::Ppt {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
@@ -352,7 +336,7 @@ impl AsusArmouryAttribute {
#[zbus(property)]
async fn current_value(&self) -> fdo::Result<i32> {
if self.name().is_ppt() || self.name().is_dgpu() {
if self.name().property_type() == FirmwareAttributeType::Ppt {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
@@ -387,66 +371,62 @@ impl AsusArmouryAttribute {
#[zbus(property)]
async fn set_current_value(&mut self, value: i32) -> fdo::Result<()> {
if self.name().is_ppt() || self.name().is_dgpu() {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
.unwrap_or_default();
let mut config = self.config.lock().await;
let tuning = config.select_tunings(power_plugged == 1, profile);
if let Some(tune) = tuning.group.get_mut(&self.name()) {
*tune = value;
} else {
tuning.group.insert(self.name(), value);
debug!("Store tuning config for {} = {:?}", self.attr.name(), value);
}
if tuning.enabled {
self.attr
.set_current_value(&AttrValue::Integer(value))
let name = self.attr.name();
let apply_value = match self.name().property_type() {
FirmwareAttributeType::Ppt => {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!(
"Could not set value to PPT property {}: {e:?}",
self.attr.name()
);
error!("Could not get power status: {e:?}");
e
})?;
} else {
warn!(
"Tuning group is disabled: skipping setting value to PPT property {}",
self.attr.name()
);
}
} else {
self.attr
.set_current_value(&AttrValue::Integer(value))
.map_err(|e| {
error!(
"Could not set value {value} to attribute {}: {e:?}",
self.attr.name()
);
e
})?;
})
.unwrap_or_default();
let mut settings = self.config.lock().await;
settings
.armoury_settings
.entry(self.name())
.and_modify(|setting| {
debug!("Set config for {} = {value}", self.attr.name());
*setting = value;
})
.or_insert_with(|| {
debug!("Adding config for {} = {value}", self.attr.name());
value
});
}
let mut config = self.config.lock().await;
let tuning = config.select_tunings(power_plugged == 1, profile);
if let Some(tune) = tuning.group.get_mut(&self.name()) {
*tune = value;
} else {
tuning.group.insert(self.name(), value);
debug!("Store tuning config for {name} = {:?}", value);
}
match tuning.enabled {
true => {
debug!("Tuning is enabled: setting value to PPT property {name} = {value}");
AttrValue::Integer(value)
}
false => {
warn!("Tuning is disabled: skipping setting value to PPT property {name}");
AttrValue::None
}
}
}
_ => {
let mut settings = self.config.lock().await;
settings
.armoury_settings
.entry(self.name())
.and_modify(|setting| {
debug!("Set config for {name} = {value}");
*setting = value;
})
.or_insert_with(|| {
debug!("Adding config for {name} = {value}");
value
});
AttrValue::Integer(value)
}
};
self.attr.set_current_value(&apply_value).map_err(|e| {
error!("Could not set value {value} to attribute {name}: {e:?}");
e
})?;
// write config after setting value
self.config.lock().await.write();
@@ -515,7 +495,7 @@ pub async fn set_config_or_default(
) {
for attr in attrs.attributes().iter() {
let name: FirmwareAttribute = attr.name().into();
if name.is_ppt() || name.is_dgpu() {
if name.property_type() == FirmwareAttributeType::Ppt {
let tuning = config.select_tunings(power_plugged, profile);
if !tuning.enabled {
debug!("Tuning group is not enabled, skipping");

View File

@@ -25,6 +25,30 @@ pub struct Aura {
impl Aura {
/// Initialise the device if required.
pub async fn do_initialization(&self) -> Result<(), RogError> {
if let Some(hid) = &self.hid {
let hid = hid.lock().await;
let init_1: [u8; 2] = [
0x5d, 0xb9,
];
let init_2 = b"]ASUS Tech.Inc.";
let init_3: [u8; 6] = [
0x5d, 0x05, 0x20, 0x31, 0, 0x1a,
];
hid.write_bytes(&init_1)?;
hid.write_bytes(init_2)?;
hid.write_bytes(&init_3)?;
let config = self.config.lock().await;
if config.support_data.device_name.contains("GZ30")
|| config.support_data.device_name.contains("Z13")
{
let z13_init: [u8; 4] = [
0x5d, 0xc0, 0x03, 0x01,
];
hid.write_bytes(&z13_init)?;
}
}
Ok(())
}
@@ -152,9 +176,54 @@ impl Aura {
}
}
let bytes = config.enabled.to_bytes(config.led_type);
let mut enabled = config.enabled.clone();
if config.support_data.device_name.contains("GZ30")
|| config.support_data.device_name.contains("Z13")
{
let logo_state = enabled
.states
.iter()
.find(|s| s.zone == PowerZones::Logo)
.cloned();
if let Some(logo) = logo_state {
let mut lid_found = false;
let mut bar_found = false;
for s in enabled.states.iter_mut() {
if s.zone == PowerZones::Lid {
s.boot = logo.boot;
s.awake = logo.awake;
s.sleep = logo.sleep;
s.shutdown = logo.shutdown;
lid_found = true;
}
if s.zone == PowerZones::Lightbar {
s.boot = logo.boot;
s.awake = logo.awake;
s.sleep = logo.sleep;
s.shutdown = logo.shutdown;
bar_found = true;
}
}
if !lid_found {
let mut new_state = logo;
new_state.zone = PowerZones::Lid;
enabled.states.push(new_state.clone());
new_state.zone = PowerZones::Lightbar;
enabled.states.push(new_state);
} else if !bar_found {
// Lid found but not bar?
let mut new_state = logo;
new_state.zone = PowerZones::Lightbar;
enabled.states.push(new_state);
}
}
}
let bytes = enabled.to_bytes(config.led_type);
let msg = [
0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], bytes[3],
0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], bytes[3], 0xff,
];
hid_raw.write_bytes(&msg)?;
}

View File

@@ -4,7 +4,9 @@ use std::sync::Arc;
use config_traits::StdConfig;
use log::{debug, error, info, warn};
use rog_platform::asus_armoury::{AttrValue, FirmwareAttribute, FirmwareAttributes};
use rog_platform::asus_armoury::{
AttrValue, FirmwareAttribute, FirmwareAttributeType, FirmwareAttributes,
};
use rog_platform::cpu::{CPUControl, CPUGovernor, CPUEPP};
use rog_platform::platform::{PlatformProfile, Properties, RogPlatform};
use rog_platform::power::AsusPower;
@@ -617,7 +619,7 @@ impl CtrlPlatform {
for attr in self.attributes.attributes() {
let name: FirmwareAttribute = attr.name().into();
if name.is_ppt() {
if name.property_type() == FirmwareAttributeType::Ppt {
// reset stored value
if let Some(tune) = self
.config

View File

@@ -980,6 +980,24 @@
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "GZ302",
product_id: "18c6",
layout_name: "",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Logo],
),
(
device_name: "GZ302",
product_id: "1a30",
layout_name: "ga401q",
basic_modes: [Static, Breathe, Pulse],
basic_zones: [],
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "RC71L",
product_id: "",

View File

@@ -123,7 +123,8 @@ impl AuraPowerState {
| ((self.shutdown as u32) << 7)
}
PowerZones::Lightbar => {
((self.boot as u32) << (7 + 2))
((self.awake as u32) << (7 + 1))
| ((self.boot as u32) << (7 + 2))
| ((self.awake as u32) << (7 + 3))
| ((self.sleep as u32) << (7 + 4))
| ((self.shutdown as u32) << (7 + 5))
@@ -133,12 +134,20 @@ impl AuraPowerState {
| ((self.awake as u32) << (15 + 2))
| ((self.sleep as u32) << (15 + 3))
| ((self.shutdown as u32) << (15 + 4))
| ((self.boot as u32) << (15 + 5))
| ((self.awake as u32) << (15 + 6))
| ((self.sleep as u32) << (15 + 7))
| ((self.shutdown as u32) << (15 + 8))
}
PowerZones::RearGlow => {
((self.boot as u32) << (23 + 1))
| ((self.awake as u32) << (23 + 2))
| ((self.sleep as u32) << (23 + 3))
| ((self.shutdown as u32) << (23 + 4))
| ((self.boot as u32) << (23 + 5))
| ((self.awake as u32) << (23 + 6))
| ((self.sleep as u32) << (23 + 7))
| ((self.shutdown as u32) << (23 + 8))
}
PowerZones::None | PowerZones::KeyboardAndLightbar => 0,
}
@@ -618,19 +627,19 @@ mod test {
assert_eq!(shut_keyb_, "10000000, 00000000, 00000000, 00000000");
//
assert_eq!(boot_bar__, "00000000, 00000010, 00000000, 00000000");
assert_eq!(awake_bar_, "00000000, 00000100, 00000000, 00000000");
assert_eq!(awake_bar_, "00000000, 00000101, 00000000, 00000000");
assert_eq!(sleep_bar_, "00000000, 00001000, 00000000, 00000000");
assert_eq!(shut_bar__, "00000000, 00010000, 00000000, 00000000");
//
assert_eq!(boot_lid__, "00000000, 00000000, 00000001, 00000000");
assert_eq!(awake_lid_, "00000000, 00000000, 00000010, 00000000");
assert_eq!(sleep_lid_, "00000000, 00000000, 00000100, 00000000");
assert_eq!(shut_lid__, "00000000, 00000000, 00001000, 00000000");
assert_eq!(boot_lid__, "00000000, 00000000, 00010001, 00000000");
assert_eq!(awake_lid_, "00000000, 00000000, 00100010, 00000000");
assert_eq!(sleep_lid_, "00000000, 00000000, 01000100, 00000000");
assert_eq!(shut_lid__, "00000000, 00000000, 10001000, 00000000");
//
assert_eq!(boot_rear_, "00000000, 00000000, 00000000, 00000001");
assert_eq!(awake_rear, "00000000, 00000000, 00000000, 00000010");
assert_eq!(sleep_rear, "00000000, 00000000, 00000000, 00000100");
assert_eq!(shut_rear_, "00000000, 00000000, 00000000, 00001000");
assert_eq!(boot_rear_, "00000000, 00000000, 00000000, 00010001");
assert_eq!(awake_rear, "00000000, 00000000, 00000000, 00100010");
assert_eq!(sleep_rear, "00000000, 00000000, 00000000, 01000100");
assert_eq!(shut_rear_, "00000000, 00000000, 00000000, 10001000");
// All on
let byte1 = to_binary_string_post2021(&LaptopAuraPower {
@@ -657,6 +666,6 @@ mod test {
},
],
});
assert_eq!(byte1, "11111111, 00011110, 00001111, 00001111");
assert_eq!(byte1, "11111111, 00011111, 11111111, 11111111");
}
}

View File

@@ -106,10 +106,10 @@ impl From<&str> for AuraDeviceType {
match s.to_lowercase().trim_start_matches("0x") {
"tuf" => AuraDeviceType::LaptopKeyboardTuf,
"1932" => AuraDeviceType::ScsiExtDisk,
"1866" | "18c6" | "1869" | "1854" => Self::LaptopKeyboardPre2021,
"1866" | "1869" | "1854" => Self::LaptopKeyboardPre2021,
"1abe" | "1b4c" => Self::Ally,
"19b3" | "193b" => Self::AnimeOrSlash,
"19b6" => Self::LaptopKeyboard2021,
"19b6" | "1a30" | "18c6" => Self::LaptopKeyboard2021,
_ => Self::Unknown,
}
}

View File

@@ -102,8 +102,9 @@ pub fn setup_window(config: Arc<Mutex<Config>>) -> MainWindow {
available.contains(&"xyz.ljones.Aura".to_string()),
available.contains(&"xyz.ljones.Anime".to_string()),
available.contains(&"xyz.ljones.FanCurves".to_string()),
true,
true,
true, // GPU Configuration
true, // App Settings
true, // About
]
.into(),
);

View File

@@ -7,6 +7,7 @@ import { PageFans } from "pages/fans.slint";
import { PageAnime, AnimePageData } from "pages/anime.slint";
import { RogItem } from "widgets/common.slint";
import { PageAura } from "pages/aura.slint";
import { PageGPU } from "pages/gpu.slint";
import { Node } from "widgets/graph.slint";
export { Node }
import { FanPageData, FanType, Profile } from "types/fan_types.slint";
@@ -24,7 +25,15 @@ export component MainWindow inherits Window {
default-font-size: 14px;
default-font-weight: 400;
icon: @image-url("../data/rog-control-center.png");
in property <[bool]> sidebar_items_avilable: [true, true, true, true, true, true];
in property <[bool]> sidebar_items_avilable: [
true,
true,
true,
true,
true, // GPU Configuration
true, // App Settings
true, // About
];
private property <bool> show_notif;
private property <bool> fade_cover;
private property <bool> toast: false;
@@ -47,37 +56,31 @@ export component MainWindow inherits Window {
}
min-height: AppSize.height;
min-width: AppSize.width;
background: Colors.black;
background: Palette.alternate-background;
HorizontalLayout {
padding: 0px;
VerticalLayout {
padding: 0px;
side-bar := SideBar {
title: @tr("ROG");
model: [
@tr("Menu1" => "System Control"),
@tr("Menu2" => "Keyboard Aura"),
@tr("Menu3" => "AniMe Matrix"),
@tr("Menu4" => "Fan Curves"),
@tr("Menu5" => "App Settings"),
@tr("Menu6" => "About"),
@tr("Menu5" => "GPU Configuration"),
@tr("Menu6" => "App Settings"),
@tr("Menu7" => "About"),
];
available: root.sidebar_items_avilable;
}
Rectangle {
max-height: 40px;
Button {
height: 40px;
width: side-bar.width;
background: Palette.control-background;
Text {
vertical-alignment: center;
horizontal-alignment: center;
text: @tr("Quit App");
}
TouchArea {
clicked => {
root.exit-app();
}
text: @tr("Quit App");
clicked() => {
root.exit-app();
}
}
}
@@ -89,26 +92,61 @@ export component MainWindow inherits Window {
height: root.height + 12px;
}
aura := PageAura {
/*if(side-bar.current-item == 1):*/ aura := PageAura {
width: root.width - side-bar.width;
visible: side-bar.current-item == 1;
}
if(side-bar.current-item == 2): PageAnime {
width: root.width - side-bar.width;
visible: side-bar.current-item == 2;
}
fans := PageFans {
if(side-bar.current-item == 3): fans := PageFans {
width: root.width - side-bar.width;
visible: side-bar.current-item == 3;
}
if(side-bar.current-item == 4): PageAppSettings {
if(side-bar.current-item == 4): PageGPU {
width: root.width - side-bar.width;
visible: side-bar.current-item == 4;
}
if(side-bar.current-item == 5): PageAbout {
if(side-bar.current-item == 5): PageAppSettings {
width: root.width - side-bar.width;
visible: side-bar.current-item == 5;
}
if(side-bar.current-item == 6): PageAbout {
width: root.width - side-bar.width;
visible: side-bar.current-item == 6;
}
if toast: Rectangle {
x: 0px;
y: root.height - self.height;
width: root.width - side-bar.width;
height: 40px;
opacity: 1.0;
background: Palette.selection-background;
clip: true;
TouchArea {
height: 100%;
width: 100%;
clicked => {
toast = false;
}
}
Rectangle {
height: 100%;
width: 100%;
background: Palette.control-background;
Text {
color: Palette.control-foreground;
text: root.toast_text;
}
}
}
}
}
@@ -133,31 +171,6 @@ export component MainWindow inherits Window {
}
}
if toast: Rectangle {
x: 0px;
y: 0px;
width: root.width;
height: 32px;
opacity: 1.0;
background: Colors.grey;
TouchArea {
height: 100%;
width: 100%;
clicked => {
toast = false;
}
}
Rectangle {
height: 100%;
width: 100%;
background: Palette.control-background;
Text {
color: Palette.control-foreground;
text: root.toast_text;
}
}
}
// // TODO: or use Dialogue
if show_notif: Rectangle {
@@ -190,10 +203,6 @@ export component MainWindow inherits Window {
y: 0px;
width: root.width;
height: root.height;
//padding only has effect on layout elements
//padding: 10px;
background: Palette.background;
border-color: Palette.border;
border-width: 3px;

View File

@@ -1,62 +1,77 @@
import { AboutSlint, VerticalBox, HorizontalBox } from "std-widgets.slint";
import {
AboutSlint,
VerticalBox,
HorizontalBox,
ScrollView,
} from "std-widgets.slint";
export component PageAbout inherits VerticalLayout {
padding: 10px;
spacing: 10px;
Text {
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
text: "A UI for asusctl made with slint";
font-size: 22px;
}
ScrollView {
HorizontalBox {
alignment: LayoutAlignment.center;
VerticalBox {
HorizontalBox {
alignment: LayoutAlignment.center;
VerticalBox {
alignment: LayoutAlignment.center;
Text {
wrap: TextWrap.word-wrap;
text: "You need to use kernel version 6.19 to use this software";
}
Text {
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
text: "ROG Control Center";
font-size: 22px;
}
Text {
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
text: "Todo:";
font-size: 22px;
}
Text {
wrap: TextWrap.word-wrap;
text: "\nA powerful graphical interface for managing ASUS ROG, TUF, and ProArt laptops on Linux. It acts as the official GUI for the asusctl toolset, allowing for seamless hardware tuning without the command line.";
}
Text {
text: "- [ ] Theme the widgets";
}
Text {
font-weight: 900;
text: "Key Features:";
}
Text {
text: "- [ ] Add a cpu/gpu temp/fan speed info bar";
}
Text {
text: " • Performance: Switch power profiles and customize fan curves.\n • Aura Sync: Control keyboard backlighting and LED effects.\n • Battery Health: Set charge limits to extend battery longevity.\n • Display: Toggle Panel Overdrive and refresh rates.\n • AniMe Matrix: Control AniMe Matrix displays.";
}
Text {
text: "- [ ] Include fan speeds, temps in a bottom bar";
}
Text {
font-weight: 900;
text: "Requirements:";
}
Text {
text: "- [ ] Slash control";
}
Text {
text: " • This software requires kernel version 6.19.";
}
Text {
text: "- [ ] Screenpad controls";
}
Text {
font-weight: 900;
text: "Work in progress:";
}
Text {
text: "- [ ] ROG Ally specific settings";
Text {
text: " • Theme the widgets\n • Add a cpu/gpu temp/fan speed info bar\n • Include fan speeds, temps in a bottom bar\n • Slash control\n • Screenpad controls\n • ROG Ally specific settings";
}
Text {
font-weight: 900;
text: "License:";
}
Text {
text: " This project is open-source software licensed under the Mozilla Public License 2.0 (MPL-2.0).";
}
Text {
font-weight: 900;
text: "Links:";
}
Text {
text: " Source Code: https://gitlab.com/asus-linux/asusctl\n Website: https://asus-linux.org/";
}
}
}
}
Text {
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
text: "Work in progress";
font-size: 22px;
}
}

View File

@@ -36,12 +36,8 @@ export component PageAnime inherits Rectangle {
property <bool> show_display_advanced: false;
property <bool> show_builtin_advanced: false;
clip: true;
// TODO: slow with border-radius
//padding only has effect on layout elements
//padding: 8px;
// height: parent.height - infobar.height - mainview.padding - self.padding * 2;
// TODO: border-radius: 8px;
VerticalLayout {
VerticalLayout {
padding: 10px;
spacing: 10px;
HorizontalLayout {
@@ -132,8 +128,9 @@ export component PageAnime inherits Rectangle {
width: 100%;
height: 100%;
opacity: 1;
background: Palette.background;
VerticalLayout {
padding: 50px;
padding: 4px;
spacing: 10px;
GroupBox {
height: 10px;
@@ -141,7 +138,7 @@ export component PageAnime inherits Rectangle {
spacing: 10px;
alignment: LayoutAlignment.start;
Text {
font-size: 18px;
font-size: 16px;
color: Palette.control-foreground;
horizontal-alignment: TextHorizontalAlignment.center;
text: @tr("Set which builtin animations are played");
@@ -193,8 +190,8 @@ export component PageAnime inherits Rectangle {
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "X";
height: 40px;
text: "";
height: 36px;
clicked => {
root.show_builtin_advanced = false;
root.show_fade_cover = false;
@@ -206,8 +203,9 @@ export component PageAnime inherits Rectangle {
width: 100%;
height: 100%;
opacity: 1;
background: Palette.background;
VerticalLayout {
padding: 50px;
padding: 4px;
spacing: 10px;
GroupBox {
height: 100px;
@@ -215,7 +213,7 @@ export component PageAnime inherits Rectangle {
spacing: 10px;
alignment: LayoutAlignment.start;
Text {
font-size: 18px;
font-size: 16px;
color: Palette.control-foreground;
horizontal-alignment: TextHorizontalAlignment.center;
text: @tr("Advanced Display Settings");
@@ -254,8 +252,8 @@ export component PageAnime inherits Rectangle {
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "X";
height: 40px;
text: "";
height: 36px;
clicked => {
root.show_display_advanced = false;
root.show_fade_cover = false;

View File

@@ -15,12 +15,7 @@ export global AppSettingsPageData {
export component PageAppSettings inherits VerticalLayout {
Rectangle {
clip: true;
// TODO: slow with border-radius
//padding only has effect on layout elements
//padding: 8px;
// height: parent.height - infobar.height - mainview.padding - self.padding * 2;
// TODO: border-radius: 8px;
mainview := VerticalLayout {
padding: 10px;
spacing: 10px;
@@ -57,7 +52,8 @@ export component PageAppSettings inherits VerticalLayout {
}
Text {
text: "WIP: some features like notifications are not complete";
color: Palette.accent-background;
text: " WIP: some features like notifications are not complete";
}
}
}

View File

@@ -17,6 +17,7 @@ export component PageAura inherits Rectangle {
c2.final_colour = AuraPageData.led_mode_data.colour2;
c2.external_colour_change();
}
ScrollView {
VerticalLayout {
padding: 10px;
@@ -53,6 +54,7 @@ export component PageAura inherits Rectangle {
min-height: 220px;
max-height: 400px;
HorizontalLayout {
padding-top: 5px;
spacing: 10px;
VerticalBox {
Text {
@@ -113,8 +115,6 @@ export component PageAura inherits Rectangle {
min-height: 80px;
max-height: 90px;
RogItem {
//padding only has effect on layout elements
//padding: 0px;
VerticalBox {
Text {
text: @tr("Zone");
@@ -137,8 +137,6 @@ export component PageAura inherits Rectangle {
}
RogItem {
//padding only has effect on layout elements
//padding: 0px;
VerticalBox {
Text {
text: @tr("Direction");
@@ -160,8 +158,6 @@ export component PageAura inherits Rectangle {
}
RogItem {
//padding only has effect on layout elements
//padding: 0px;
VerticalBox {
Text {
text: @tr("Speed");
@@ -205,6 +201,7 @@ export component PageAura inherits Rectangle {
}
if root.show_aura_power && AuraPageData.device_type == AuraDevType.New: Rectangle {
background: Palette.background;
width: 100%;
height: 100%;
opacity: 1;
@@ -244,8 +241,8 @@ export component PageAura inherits Rectangle {
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "X";
height: 40px;
text: "";
height: 36px;
clicked => {
root.show_aura_power = false;
root.show_fade_cover = false;
@@ -255,6 +252,7 @@ export component PageAura inherits Rectangle {
}
if root.show_aura_power && AuraPageData.device_type == AuraDevType.Old: Rectangle {
background: Palette.background;
width: 100%;
height: 100%;
opacity: 1;
@@ -297,8 +295,8 @@ export component PageAura inherits Rectangle {
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "X";
height: 40px;
text: "";
height: 36px;
clicked => {
root.show_aura_power = false;
root.show_fade_cover = false;

View File

@@ -16,20 +16,28 @@ component FanTab inherits Rectangle {
in-out property <[Node]> nodes;
VerticalLayout {
padding: 5px;
HorizontalLayout {
if root.tab_enabled: Graph {
nodes <=> root.nodes;
}
if !root.tab_enabled: Rectangle {
Text {
font-size: 24px;
font-size: 16px;
text: @tr("This fan is not avilable on this machine");
}
}
}
Rectangle {
background: Palette.border;
height: 1px;
}
HorizontalLayout {
alignment: LayoutAlignment.end;
spacing: 10px;
padding: 10px;
CheckBox {
text: @tr("Enabled");
checked <=> root.enabled;

View File

@@ -0,0 +1,36 @@
import { Palette, TabWidget, Button, CheckBox, ScrollView } from "std-widgets.slint";
import { Graph, Node } from "../widgets/graph.slint";
import { SystemToggle, SystemDropdown } from "../widgets/common.slint";
import { Profile, FanType, FanPageData } from "../types/fan_types.slint";
export global GPUPageData {
// GPU mode and device state
in-out property <int> gpu_mux_mode: 1; // 0 = Ultra/Discreet, 1 = Integrated/Optimus
in-out property <int> dgpu_disabled: 0; // 1 == dGPU disabled
in-out property <int> egpu_enabled: 0; // 1 == eGPU (XGMobile) enabled
in-out property <[string]> gpu_modes_choises: [@tr("Ultra"), @tr("Integrated")];
callback cb_gpu_mux_mode(int);
callback cb_dgpu_disabled(int);
callback cb_egpu_enabled(int);
}
export component PageGPU inherits Rectangle {
clip: true;
ScrollView {
VerticalLayout {
padding: 10px;
spacing: 10px;
SystemDropdown {
text: @tr("GPU mode");
current_index <=> GPUPageData.gpu_mux_mode;
current_value: GPUPageData.gpu_modes_choises[GPUPageData.gpu_mux_mode];
model <=> GPUPageData.gpu_modes_choises;
selected => {
GPUPageData.cb_gpu_mux_mode(0);
GPUPageData.cb_gpu_mux_mode(1);
}
}
}
}
}

View File

@@ -152,21 +152,20 @@ export component PageSystem inherits Rectangle {
property <bool> show_fade_cover: false;
property <bool> show_throttle_advanced: false;
clip: true;
//padding only has effect on layout elements
//padding: 8px;
ScrollView {
VerticalLayout {
padding: 10px;
spacing: 10px;
padding: 12px;
spacing: 8px;
alignment: LayoutAlignment.start;
Rectangle {
background: Palette.alternate-background;
border-color: Palette.accent-background;
border-width: 3px;
border-radius: 10px;
height: 40px;
border-color: Palette.border;
border-width: 1px;
border-radius: 2px;
height: 36px;
Text {
font-size: 18px;
font-size: 16px;
color: Palette.control-foreground;
horizontal-alignment: TextHorizontalAlignment.center;
text: @tr("Power settings");
@@ -212,11 +211,11 @@ export component PageSystem inherits Rectangle {
padding-left: 10px;
padding-right: 20px;
HorizontalLayout {
width: 38%;
width: 40%;
alignment: LayoutAlignment.space-between;
padding-right: 15px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
text: @tr("Screenpad brightness");
@@ -240,7 +239,7 @@ export component PageSystem inherits Rectangle {
HorizontalLayout {
width: 20%;
padding-left: 10px;
padding-left: 14px;
alignment: LayoutAlignment.stretch;
Switch {
text: @tr("Sync with primary");
@@ -253,14 +252,74 @@ export component PageSystem inherits Rectangle {
}
}
if SystemPageData.kbd_leds_awake != -1 ||
SystemPageData.kbd_leds_sleep != -1 ||
SystemPageData.kbd_leds_boot != -1 ||
SystemPageData.kbd_leds_shutdown != -1: VerticalLayout {
padding: 0px;
spacing: 0px;
alignment: LayoutAlignment.start;
Rectangle {
background: Palette.alternate-background;
border-color: Palette.border;
border-width: 1px;
border-radius: 2px;
height: 40px;
Text {
font-size: 16px;
color: Palette.control-foreground;
horizontal-alignment: TextHorizontalAlignment.center;
text: @tr("Keyboard Power Management");
}
}
GroupBox {
HorizontalLayout {
spacing: 10px;
if SystemPageData.kbd_leds_awake != -1: SystemToggleInt {
text: @tr("Keyboard Awake Effect");
checked_int <=> SystemPageData.kbd_leds_awake;
toggled => {
SystemPageData.cb_kbd_leds_awake(SystemPageData.kbd_leds_awake)
}
}
if SystemPageData.kbd_leds_sleep != -1: SystemToggleInt {
text: @tr("Keyboard Sleep Effect");
checked_int <=> SystemPageData.kbd_leds_sleep;
toggled => {
SystemPageData.cb_kbd_leds_sleep(SystemPageData.kbd_leds_sleep)
}
}
if SystemPageData.kbd_leds_boot != -1: SystemToggleInt {
text: @tr("Keyboard Boot Effect");
checked_int <=> SystemPageData.kbd_leds_boot;
toggled => {
SystemPageData.cb_kbd_leds_boot(SystemPageData.kbd_leds_boot)
}
}
if SystemPageData.kbd_leds_shutdown != -1: SystemToggleInt {
text: @tr("Keyboard Shutdown Effect");
checked_int <=> SystemPageData.kbd_leds_shutdown;
toggled => {
SystemPageData.cb_kbd_leds_shutdown(SystemPageData.kbd_leds_shutdown)
}
}
}
}
}
Rectangle {
background: Palette.alternate-background;
border-color: Palette.accent-background;
border-width: 3px;
border-radius: 10px;
height: 40px;
border-color: Palette.border;
border-width: 1px;
border-radius: 2px;
height: 36px;
Text {
font-size: 18px;
font-size: 16px;
color: Palette.control-foreground;
horizontal-alignment: TextHorizontalAlignment.center;
text: @tr("Armoury settings");
@@ -268,62 +327,26 @@ export component PageSystem inherits Rectangle {
}
if !SystemPageData.asus_armoury_loaded: Rectangle {
border-width: 3px;
border-color: red;
background: maroon;
// background: darkred;
max-height: 30px;
VerticalBox {
Text {
text: @tr("no_asus_armoury_driver_1" => "The asus-armoury driver is not loaded");
font-size: 16px;
color: white;
horizontal-alignment: TextHorizontalAlignment.center;
}
Text {
text: @tr("no_asus_armoury_driver_2" => "For advanced features you will require a kernel with this driver added.");
font-size: 16px;
color: white;
horizontal-alignment: TextHorizontalAlignment.center;
}
}
}
GroupBox {
title: @tr("Keyboard Power Management");
HorizontalLayout {
spacing: 10px;
if SystemPageData.kbd_leds_awake != -1: SystemToggleInt {
text: @tr("Keyboard Awake Effect");
checked_int <=> SystemPageData.kbd_leds_awake;
toggled => {
SystemPageData.cb_kbd_leds_awake(SystemPageData.kbd_leds_awake)
}
}
if SystemPageData.kbd_leds_sleep != -1: SystemToggleInt {
text: @tr("Keyboard Sleep Effect");
checked_int <=> SystemPageData.kbd_leds_sleep;
toggled => {
SystemPageData.cb_kbd_leds_sleep(SystemPageData.kbd_leds_sleep)
}
}
if SystemPageData.kbd_leds_boot != -1: SystemToggleInt {
text: @tr("Keyboard Boot Effect");
checked_int <=> SystemPageData.kbd_leds_boot;
toggled => {
SystemPageData.cb_kbd_leds_boot(SystemPageData.kbd_leds_boot)
}
}
if SystemPageData.kbd_leds_shutdown != -1: SystemToggleInt {
text: @tr("Keyboard Shutdown Effect");
checked_int <=> SystemPageData.kbd_leds_shutdown;
toggled => {
SystemPageData.cb_kbd_leds_shutdown(SystemPageData.kbd_leds_shutdown)
}
}
}
}
HorizontalBox {
padding: 0px;
spacing: 10px;
@@ -561,20 +584,22 @@ export component PageSystem inherits Rectangle {
}
if root.show_throttle_advanced: Rectangle {
background: Palette.background;
width: 100%;
height: 100%;
opacity: 1;
ScrollView {
VerticalLayout {
padding: 50px;
padding-top: 5px;
padding-bottom: 100px;
alignment: start;
padding: 5px;
padding-top: 15px;
spacing: 10px;
GroupBox {
VerticalBox {
alignment: start;
spacing: 10px;
Text {
font-size: 18px;
font-size: 16px;
horizontal-alignment: TextHorizontalAlignment.center;
vertical-alignment: TextVerticalAlignment.center;
text: @tr("Energy Performance Preference linked to Throttle Policy");
@@ -622,9 +647,10 @@ export component PageSystem inherits Rectangle {
GroupBox {
VerticalBox {
alignment: start;
spacing: 10px;
Text {
font-size: 18px;
font-size: 16px;
horizontal-alignment: TextHorizontalAlignment.center;
vertical-alignment: TextVerticalAlignment.center;
text: @tr("Throttle Policy for power state");
@@ -679,8 +705,8 @@ export component PageSystem inherits Rectangle {
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "X";
height: 40px;
text: "";
height: 34px;
clicked => {
root.show_throttle_advanced = false;
root.show_fade_cover = false;

View File

@@ -4,8 +4,6 @@ import { PowerZones } from "../types/aura_types.slint";
export component AuraPowerGroup inherits Rectangle {
min-width: row.min-width;
border-radius: 20px;
background: Palette.alternate-background;
opacity: 0.9;
in-out property <string> group-title;
in-out property <bool> boot_checked;
@@ -16,6 +14,7 @@ export component AuraPowerGroup inherits Rectangle {
callback awake_toggled(bool);
callback sleep_toggled(bool);
callback shutdown_toggled(bool);
VerticalBox {
spacing: 10px;
Text {
@@ -28,7 +27,7 @@ export component AuraPowerGroup inherits Rectangle {
row := HorizontalBox {
alignment: LayoutAlignment.center;
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Boot");
checked <=> root.boot_checked;
@@ -38,7 +37,7 @@ export component AuraPowerGroup inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Awake");
checked <=> root.awake_checked;
@@ -48,7 +47,7 @@ export component AuraPowerGroup inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Sleep");
checked <=> root.sleep_checked;
@@ -58,7 +57,7 @@ export component AuraPowerGroup inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Shutdown");
checked <=> root.shutdown_checked;
@@ -72,8 +71,6 @@ export component AuraPowerGroup inherits Rectangle {
export component AuraPowerGroupOld inherits Rectangle {
min-width: row.min-width;
border-radius: 20px;
background: Palette.alternate-background;
opacity: 0.9;
in-out property <int> current_zone;
in-out property <[int]> zones;
@@ -86,6 +83,7 @@ export component AuraPowerGroupOld inherits Rectangle {
callback awake_toggled(bool);
callback sleep_toggled(bool);
callback selected_zone(int);
VerticalBox {
spacing: 10px;
Text {
@@ -109,7 +107,7 @@ export component AuraPowerGroupOld inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Boot");
checked <=> root.boot_checked;
@@ -119,7 +117,7 @@ export component AuraPowerGroupOld inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Awake");
checked <=> root.awake_checked;
@@ -129,7 +127,7 @@ export component AuraPowerGroupOld inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Sleep");
checked <=> root.sleep_checked;

View File

@@ -1,7 +1,7 @@
import { Palette, Slider, HorizontalBox, Button, LineEdit } from "std-widgets.slint";
export component ColourSlider inherits VerticalLayout {
spacing: 10px;
spacing: 12px;
in-out property <bool> enabled;
property <string> hex: "#FF0000";
in-out property <float> c1value <=> c1.value;
@@ -102,9 +102,9 @@ export component ColourSlider inherits VerticalLayout {
hex = set_hex_from_colour(final_colour);
}
Rectangle {
height: 32px;
border-width: 2px;
border-radius: 7px;
height: 28px;
border-width: 1px;
border-radius: 3px;
border-color: Palette.border;
// 13 colours
background: !root.enabled ? Palette.alternate-background : @linear-gradient(90deg, base_colours[0], base_colours[1], base_colours[2], base_colours[3], base_colours[4], base_colours[5], base_colours[6], base_colours[7], base_colours[8], base_colours[9], base_colours[10], base_colours[11], base_colours[12], base_colours[13], base_colours[14], base_colours[15], base_colours[16], base_colours[17], base_colours[18], base_colours[19], base_colours[20], base_colours[21], base_colours[22], base_colours[23], base_colours[24], base_colours[25], base_colours[26], base_colours[27], base_colours[28], base_colours[29], base_colours[30], base_colours[31], base_colours[32], base_colours[33], base_colours[34], base_colours[35]);
@@ -127,9 +127,9 @@ export component ColourSlider inherits VerticalLayout {
}
Rectangle {
height: 32px;
border-width: 2px;
border-radius: 7px;
height: 28px;
border-width: 1px;
border-radius: 3px;
border-color: Palette.border;
// 11 colours
background: !root.enabled ? Palette.alternate-background : @linear-gradient(90deg, base_saturation[0], base_saturation[1], base_saturation[2], base_saturation[3], base_saturation[4], base_saturation[5], base_saturation[6], base_saturation[7], base_saturation[8], base_saturation[9], base_saturation[10]);
@@ -151,9 +151,9 @@ export component ColourSlider inherits VerticalLayout {
}
Rectangle {
height: 32px;
border-width: 2px;
border-radius: 7px;
height: 28px;
border-width: 1px;
border-radius: 3px;
border-color: Palette.border;
// 11 colours
background: !root.enabled ? Palette.alternate-background : @linear-gradient(90deg, base_value[0], base_value[1], base_value[2], base_value[3], base_value[4], base_value[5], base_value[6], base_value[7], base_value[8], base_value[9], base_value[10]);
@@ -191,8 +191,8 @@ export component ColourSlider inherits VerticalLayout {
Rectangle {
width: self.height;
border-width: 2px;
border-radius: 7px;
border-width: 1px;
border-radius: 3px;
border-color: Palette.border;
background <=> root.colourbox;
}

View File

@@ -1,12 +1,11 @@
import { Palette, VerticalBox , StandardButton, Button, HorizontalBox, ComboBox, Switch, Slider} from "std-widgets.slint";
export component RogItem inherits Rectangle {
background: Palette.control-background;
border-color: Palette.border;
border-width: 3px;
border-radius: 10px;
min-height: 48px;
max-height: 56px;
border-width: 1px;
border-radius: 2px;
min-height: 44px;
max-height: 44px;
}
export component SystemSlider inherits RogItem {
@@ -30,14 +29,14 @@ export component SystemSlider inherits RogItem {
HorizontalLayout {
spacing: 6px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
text: root.text;
}
Text {
font-size: 16px;
font-size: 14px;
horizontal-alignment: TextHorizontalAlignment.right;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
@@ -47,7 +46,7 @@ export component SystemSlider inherits RogItem {
}
HorizontalBox {
padding-right: 20px;
padding-right: 10px;
slider := Slider {
enabled: root.enabled;
maximum: root.maximum;
@@ -162,7 +161,7 @@ export component SystemToggle inherits RogItem {
alignment: LayoutAlignment.start;
padding-left: 10px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
text: root.text;
@@ -193,7 +192,7 @@ export component SystemToggleInt inherits RogItem {
alignment: LayoutAlignment.start;
padding-left: 10px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
text: root.text;
@@ -223,7 +222,7 @@ export component SystemToggleVert inherits RogItem {
alignment: LayoutAlignment.space-around;
padding-top: 8px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.bottom;
horizontal-alignment: TextHorizontalAlignment.center;
color: Palette.control-foreground;
@@ -254,7 +253,7 @@ export component SystemDropdown inherits RogItem {
alignment: LayoutAlignment.start;
padding-left: 10px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
text: root.text;
@@ -291,11 +290,7 @@ export component PopupNotification {
border-width: 2px;
border-color: Palette.accent-background;
background: Palette.background;
// TODO: drop shadows slow
// drop-shadow-offset-x: 7px;
// drop-shadow-offset-y: 7px;
// drop-shadow-color: black;
// drop-shadow-blur: 30px;
VerticalLayout {
Dialog {
VerticalLayout {

View File

@@ -191,10 +191,11 @@ export component Graph inherits Rectangle {
tip := Rectangle {
background: Palette.control-foreground;
opacity: 0.3;
border-radius: 12px;
x: final_x_pos();
y: final_y_pos();
width: label.preferred-width;
height: label.preferred-height;
width: label.preferred-width + 14px;
height: label.preferred-height + 4px;
function x_pos() -> length {
scale_x_to_graph(n.x) - label.preferred-width - 8px
}
@@ -225,7 +226,7 @@ export component Graph inherits Rectangle {
//
label := Text {
color: Palette.accent-foreground;
font-size: 16px;
font-size: 14px;
text: "\{Math.floor(n.x / 1px)}c, \{fan_pct()}%";
}
}

View File

@@ -4,8 +4,6 @@
import { Palette, HorizontalBox, VerticalBox } from "std-widgets.slint";
component SideBarItem inherits Rectangle {
// padding only has effect on layout elements
// padding: 10px;
in property <bool> selected;
in property <bool> has-focus;
in-out property <string> text <=> label.text;
@@ -26,18 +24,16 @@ component SideBarItem inherits Rectangle {
state.opacity: 0.8;
}
]
state := Rectangle {
opacity: 0;
border-width: 2px;
border-radius: 10px;
border-color: Palette.accent-background;
background: Palette.alternate-background;
background: Palette.selection-background;
animate opacity { duration: 150ms; }
animate border-width { duration: 150ms; }
height: l.preferred-height;
}
l := HorizontalBox {
x: 4px;
y: (parent.height - self.height) / 2;
spacing: 0px;
label := Text {
@@ -56,20 +52,16 @@ component SideBarItem inherits Rectangle {
export component SideBar inherits Rectangle {
in property <[string]> model: [];
in property <[bool]> available: [];
in property <string> title <=> label.text;
out property <int> current-item: 0;
out property <int> current-focused: fs.has-focus ? fs.focused-tab : -1;
// The currently focused tab
width: 160px;
width: 180px;
forward-focus: fs;
accessible-role: tab;
accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current-item;
Rectangle {
border-width: 2px;
border-color: Palette.accent-background;
border-radius: 0px;
background: Palette.background.darker(0.2);
background: Palette.alternate-background;
fs := FocusScope {
key-pressed(event) => {
if (event.text == "\n") {
@@ -102,10 +94,19 @@ export component SideBar inherits Rectangle {
VerticalBox {
spacing: 4px;
padding: 0px;
alignment: start;
label := Text {
font-size: 16px;
Image {
height: 100px;
source: @image-url("../../data/rog-control-center.png");
horizontal-alignment: center;
image-fit: contain;
}
Rectangle {
height: 1px;
background: Palette.border;
}
navigation := VerticalLayout {

View File

@@ -253,8 +253,19 @@ impl FirmwareAttributes {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum FirmwareAttributeType {
#[default]
Immediate,
TUFKeyboard,
Ppt,
Gpu,
Bios,
}
macro_rules! define_attribute_getters {
($($attr:ident),*) => {
// Accept a list of attribute idents and an optional `types { .. }` block
( $( $attr:ident ),* $(,)? $( ; types { $( $tattr:ident : $ptype:ident ),* $(,)? } )? ) => {
impl FirmwareAttributes {
$(
pub fn $attr(&self) -> Option<&Attribute> {
@@ -268,6 +279,17 @@ macro_rules! define_attribute_getters {
});
)*
}
impl FirmwareAttribute {
pub fn property_type(&self) -> FirmwareAttributeType {
match <&str>::from(*self) {
$(
$( stringify!($tattr) => FirmwareAttributeType::$ptype, )*
)?
_ => FirmwareAttributeType::Immediate,
}
}
}
}
}
@@ -299,6 +321,38 @@ define_attribute_getters!(
gpu_mux_mode,
mini_led_mode,
screen_auto_brightness
; types {
ppt_pl1_spl: Ppt,
ppt_pl2_sppt: Ppt,
ppt_apu_sppt: Ppt,
ppt_platform_sppt: Ppt,
ppt_fppt: Ppt,
nv_dynamic_boost: Ppt,
nv_temp_target: Ppt,
dgpu_base_tgp: Ppt,
dgpu_tgp: Ppt,
gpu_mux_mode: Gpu,
egpu_connected: Gpu,
egpu_enable: Gpu,
dgpu_disable: Gpu,
boot_sound: Bios,
mcu_powersave: Immediate,
screen_auto_brightness: Immediate,
mini_led_mode: Immediate,
panel_hd_mode: Immediate,
panel_od: Immediate,
kbd_leds_awake: TUFKeyboard,
kbd_leds_sleep: TUFKeyboard,
kbd_leds_boot: TUFKeyboard,
kbd_leds_shutdown: TUFKeyboard,
charge_mode: Immediate,
}
);
/// CamelCase names of the properties. Intended for use with DBUS
@@ -352,29 +406,6 @@ pub enum FirmwareAttribute {
KbdLedsShutdown = 30,
}
impl FirmwareAttribute {
pub fn is_ppt(&self) -> bool {
matches!(
self,
FirmwareAttribute::PptPl1Spl
| FirmwareAttribute::PptPl2Sppt
| FirmwareAttribute::PptPl3Fppt
| FirmwareAttribute::PptFppt
| FirmwareAttribute::PptApuSppt
| FirmwareAttribute::PptPlatformSppt
)
}
pub fn is_dgpu(&self) -> bool {
matches!(
self,
FirmwareAttribute::NvDynamicBoost
| FirmwareAttribute::NvTempTarget
| FirmwareAttribute::DgpuTgp
)
}
}
impl From<&str> for FirmwareAttribute {
fn from(s: &str) -> Self {
match s {

View File

@@ -162,7 +162,6 @@ impl CurveData {
/// Write this curve to the device fan specified by `self.fan`
pub fn write_to_device(&self, device: &mut Device) -> std::io::Result<()> {
let pwm_num: char = self.fan.into();
let enable = if self.enabled { '1' } else { '2' };
for (index, out) in self.pwm.iter().enumerate() {
let pwm = pwm_str(pwm_num, index);
@@ -176,10 +175,20 @@ impl CurveData {
device.set_attribute_value(&temp, out.to_string())?;
}
// Enable must be done *after* all points are written pwm3_enable
// Note: pwm_enable is set by write_profile_curve_to_platform after all
// curves are written, because on some devices (e.g., ASUS Z13 2025)
// setting any pwm_enable to 2 resets ALL fan enables.
Ok(())
}
/// Set the enable state for this fan curve
pub fn set_enable(&self, device: &mut Device) -> std::io::Result<()> {
let pwm_num: char = self.fan.into();
let enable = if self.enabled { "1" } else { "2" };
let enable_attr = format!("pwm{pwm_num}_enable");
device
.set_attribute_value(format!("pwm{pwm_num}_enable"), enable.to_string())
.map_err(|e| error!("Failed to set pwm{pwm_num}_enable to {enable}: {e:?}"))
.set_attribute_value(&enable_attr, enable.to_string())
.map_err(|e| error!("Failed to set {enable_attr} to {enable}: {e:?}"))
.ok();
Ok(())
}

View File

@@ -181,15 +181,29 @@ impl FanCurveProfiles {
PlatformProfile::Quiet | PlatformProfile::LowPower => &mut self.quiet,
PlatformProfile::Custom => &mut self.custom,
};
for fan in fans.iter().filter(|f| !f.enabled) {
debug!("write_profile_curve_to_platform: writing profile:{profile}, {fan:?}");
// First write all curve data (pwm/temp values) for all fans
for fan in fans.iter() {
debug!("write_profile_curve_to_platform: writing curve data for profile:{profile}, {fan:?}");
fan.write_to_device(device)?;
}
// Write enabled fans last because the kernel currently resets *all* if one is
// disabled
// Then set enables: disabled fans first, then enabled fans last.
// This order is important because on some devices (e.g., ASUS Z13 2025)
// setting any pwm_enable to 2 (disabled) resets ALL fan enables.
for fan in fans.iter().filter(|f| !f.enabled) {
debug!(
"write_profile_curve_to_platform: disabling fan for profile:{profile}, {:?}",
fan.fan
);
fan.set_enable(device)?;
}
for fan in fans.iter().filter(|f| f.enabled) {
debug!("write_profile_curve_to_platform: writing profile:{profile}, {fan:?}");
fan.write_to_device(device)?;
debug!(
"write_profile_curve_to_platform: enabling fan for profile:{profile}, {:?}",
fan.fan
);
fan.set_enable(device)?;
}
Ok(())
}