diff --git a/lact-gui/src/app/pages/oc_page/clocks_frame.rs b/lact-gui/src/app/pages/oc_page/clocks_frame.rs index aaa12ca..6b84eaa 100644 --- a/lact-gui/src/app/pages/oc_page/clocks_frame.rs +++ b/lact-gui/src/app/pages/oc_page/clocks_frame.rs @@ -8,13 +8,16 @@ use adjustment_row::{ClockAdjustmentRow, ClockAdjustmentRowMsg, ClocksData}; use amdgpu_sysfs::gpu_handle::overdrive::{ClocksTable as _, ClocksTableGen as AmdClocksTable}; use gtk::{ pango, - prelude::{BoxExt, ButtonExt, OrientableExt, WidgetExt}, + prelude::{BoxExt, ButtonExt, CheckButtonExt, OrientableExt, WidgetExt}, }; use lact_schema::{ request::{ClockspeedType, SetClocksCommand}, ClocksTable, IntelClocksTable, NvidiaClockOffset, NvidiaClocksTable, }; -use relm4::{factory::FactoryHashMap, ComponentParts, ComponentSender, RelmWidgetExt}; +use relm4::{ + binding::BoolBinding, factory::FactoryHashMap, ComponentParts, ComponentSender, RelmObjectExt, + RelmWidgetExt, +}; // This is only used on RDNA1 in practice const DEFAULT_VOLTAGE_OFFSET_RANGE: i32 = 250; @@ -23,12 +26,15 @@ const WARNING_TEXT: &str = "Warning: changing these values may lead to system in pub struct ClocksFrame { clocks: FactoryHashMap, vram_clock_ratio: f64, + show_nvidia_pstate_info: bool, + show_all_pstates: BoolBinding, } #[derive(Debug)] pub enum ClocksFrameMsg { Clocks(Option), VramRatio(f64), + TogglePStatesVisibility, } #[relm4::component(pub)] @@ -43,12 +49,36 @@ impl relm4::SimpleComponent for ClocksFrame { set_label: WARNING_TEXT, set_wrap_mode: pango::WrapMode::Word, set_halign: gtk::Align::Start, - set_margin_vertical: 5, + set_margin_horizontal: 5, + }, + + append = >k::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 5, + + #[watch] + set_visible: model.show_nvidia_pstate_info, + + append = >k::CheckButton { + set_label: Some("Show all P-States"), + add_binding["active"]: &model.show_all_pstates, + }, + + append = >k::Label { + add_binding["visible"]: &model.show_all_pstates, + + set_margin_horizontal: 5, + set_markup: "The following values are clock offsets for each P-State, going from highest to lowest.", + set_wrap_mode: pango::WrapMode::Word, + set_halign: gtk::Align::Start, + }, + }, append = model.clocks.widget() { set_orientation: gtk::Orientation::Vertical, set_spacing: 5, + set_margin_horizontal: 5, }, append = >k::Label { @@ -62,7 +92,7 @@ impl relm4::SimpleComponent for ClocksFrame { append = >k::Button { set_label: "Reset", set_halign: gtk::Align::End, - set_width_request: 75, + set_margin_horizontal: 5, set_tooltip_text: Some("Warning: this resets all clock settings to defaults!"), set_css_classes: &["destructive-action"], #[watch] @@ -78,15 +108,21 @@ impl relm4::SimpleComponent for ClocksFrame { fn init( _init: Self::Init, root: Self::Root, - _sender: ComponentSender, + sender: ComponentSender, ) -> ComponentParts { let clocks = FactoryHashMap::builder().launch_default().detach(); let model = Self { clocks, vram_clock_ratio: 1.0, + show_nvidia_pstate_info: false, + show_all_pstates: BoolBinding::new(false), }; + model + .show_all_pstates + .connect_value_notify(move |_| sender.input(ClocksFrameMsg::TogglePStatesVisibility)); + let widgets = view_output!(); ComponentParts { model, widgets } @@ -96,6 +132,8 @@ impl relm4::SimpleComponent for ClocksFrame { match msg { ClocksFrameMsg::Clocks(clocks_table) => { self.clocks.clear(); + self.show_nvidia_pstate_info = false; + self.show_all_pstates.set_value(false); if let Some(table) = clocks_table { match table { @@ -104,10 +142,31 @@ impl relm4::SimpleComponent for ClocksFrame { ClocksTable::Intel(table) => self.set_intel_table(table), } } + + // Make sure the width of all the labels is the same + let label_size_group = gtk::SizeGroup::new(gtk::SizeGroupMode::Horizontal); + let input_size_group = gtk::SizeGroup::new(gtk::SizeGroupMode::Horizontal); + + for clockspeed_type in self.clocks.keys() { + self.clocks.send( + clockspeed_type, + ClockAdjustmentRowMsg::AddSizeGroup { + label_group: label_size_group.clone(), + input_group: input_size_group.clone(), + }, + ); + } } ClocksFrameMsg::VramRatio(vram_ratio) => { self.vram_clock_ratio = vram_ratio; } + ClocksFrameMsg::TogglePStatesVisibility => { + let show = self.show_all_pstates.value(); + for key in self.clocks.keys() { + self.clocks + .send(key, ClockAdjustmentRowMsg::ShowSecondaryPStates(show)); + } + } } self.update_vram_clock_ratio(); } @@ -190,6 +249,8 @@ impl ClocksFrame { } fn set_nvidia_table(&mut self, table: NvidiaClocksTable) { + self.show_nvidia_pstate_info = true; + for (pstate, offset) in table.gpu_offsets { self.clocks.insert( ClockspeedType::GpuClockOffset(pstate), diff --git a/lact-gui/src/app/pages/oc_page/clocks_frame/adjustment_row.rs b/lact-gui/src/app/pages/oc_page/clocks_frame/adjustment_row.rs index 9a0d1a5..07f1726 100644 --- a/lact-gui/src/app/pages/oc_page/clocks_frame/adjustment_row.rs +++ b/lact-gui/src/app/pages/oc_page/clocks_frame/adjustment_row.rs @@ -25,6 +25,11 @@ pub struct ClocksData { #[derive(Debug)] pub enum ClockAdjustmentRowMsg { ValueRatio(f64), + ShowSecondaryPStates(bool), + AddSizeGroup { + label_group: gtk::SizeGroup, + input_group: gtk::SizeGroup, + }, } #[relm4::factory(pub)] @@ -37,11 +42,13 @@ impl FactoryComponent for ClockAdjustmentRow { type Index = ClockspeedType; view! { + #[name = "root_box"] gtk::Box { + #[name = "title_label"] gtk::Label { - set_width_request: 185, set_xalign: 0.0, - set_label: &match self.clock_type { + #[watch] + set_markup: &match self.clock_type { ClockspeedType::MaxCoreClock => "Maximum GPU Clock (MHz)".to_owned(), ClockspeedType::MaxMemoryClock => "Maximum VRAM Clock (MHz)".to_owned(), ClockspeedType::MaxVoltage => "Maximum GPU voltage (mV)".to_owned(), @@ -49,10 +56,10 @@ impl FactoryComponent for ClockAdjustmentRow { ClockspeedType::MinMemoryClock => "Minimum VRAM Clock (MHz)".to_owned(), ClockspeedType::MinVoltage => "Minimum GPU voltage (mV)".to_owned(), ClockspeedType::VoltageOffset => "GPU voltage offset (mV)".to_owned(), - ClockspeedType::GpuClockOffset(pstate) => format!("GPU Clock offset at P-State {pstate} (MHz)"), - ClockspeedType::MemClockOffset(pstate) => format!("VRAM Clock offset at P-State {pstate} (MHz)"), + ClockspeedType::GpuClockOffset(pstate) => format!("GPU P-State {pstate} Clock Offset (MHz)"), + ClockspeedType::MemClockOffset(pstate) => format!("VRAM P-State {pstate} Clock Offset (MHz)"), ClockspeedType::Reset => unreachable!(), - }, + } }, gtk::Scale { @@ -65,9 +72,9 @@ impl FactoryComponent for ClockAdjustmentRow { set_margin_horizontal: 5, }, + #[name = "input_button"] gtk::SpinButton { set_adjustment: &self.adjustment, - set_width_request: 120, }, } } @@ -98,7 +105,12 @@ impl FactoryComponent for ClockAdjustmentRow { } } - fn update(&mut self, msg: Self::Input, _sender: relm4::FactorySender) { + fn update_with_view( + &mut self, + widgets: &mut Self::Widgets, + msg: Self::Input, + sender: relm4::FactorySender, + ) { match msg { ClockAdjustmentRowMsg::ValueRatio(ratio) => { self.adjustment.block_signal(&self.change_signal); @@ -115,7 +127,20 @@ impl FactoryComponent for ClockAdjustmentRow { self.adjustment.unblock_signal(&self.change_signal); } + ClockAdjustmentRowMsg::AddSizeGroup { + label_group, + input_group, + } => { + label_group.add_widget(&widgets.title_label); + input_group.add_widget(&widgets.input_button); + } + ClockAdjustmentRowMsg::ShowSecondaryPStates(show_secondary) => { + let show_current = show_secondary || !clock_type_is_secondary(&self.clock_type); + widgets.root_box.set_visible(show_current); + } } + + self.update_view(widgets, sender); } } @@ -126,3 +151,11 @@ impl ClockAdjustmentRow { .map(|value| (value / self.value_ratio) as i32) } } + +fn clock_type_is_secondary(clock_type: &ClockspeedType) -> bool { + match clock_type { + ClockspeedType::GpuClockOffset(pstate) => *pstate > 0, + ClockspeedType::MemClockOffset(pstate) => *pstate > 0, + _ => false, + } +}