mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2026-08-17 16:34:54 -05:00
feat: support multi-column layout for adjustment-rows lists (#892)
* move box styles * split into 2 lists * wrap into flow-box * clean up clean up clean up clean up replace get_factory with less verbose set_clock method * fmt * split Adjustment rows into multiple groups * try columns * wip * finish markup * move nvidia OC info popover * fmt * remove comments from schema * fmt * refactor * add adjustment groups * change warning text * upd spacing * move AdjustmentGroups * refactor: make AdjustmentGroup a factory component, create them dynamically * fix layout * chore: drop unused param * remove misleading comment --------- Co-authored-by: Ilya Zlobintsev <ilya.zl@protonmail.com>
This commit is contained in:
co-authored by
Ilya Zlobintsev
parent
02037ddea6
commit
d39b963ca3
@@ -154,7 +154,7 @@ nvidia-oc-description =
|
||||
It is possible to achieve a pseudo-undervolt by combining the locked clocks option with a positive clockspeed offset.
|
||||
This will force the GPU to run at a voltage that's constrained by the locked clocks, while achieving a higher clockspeed due to the offset.
|
||||
This can cause system instability if pushed too high.
|
||||
oc-warning = Warning: changing these values may lead to system instability and can potentially damage your hardware!
|
||||
oc-warning = Changing these values may lead to system instability and can potentially damage your hardware!
|
||||
show-all-pstates = Show all P-States
|
||||
enable-gpu-locked-clocks = Enable GPU Locked Clocks
|
||||
enable-vram-locked-clocks = Enable VRAM Locked Clocks
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.page-section-content {
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.page-section-children-box {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
@@ -102,8 +102,8 @@ mod imp {
|
||||
|
||||
#[local_ref]
|
||||
append = children_box {
|
||||
add_css_class: "page-section-children-box",
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_margin_all: 10,
|
||||
set_spacing: 10,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
.clocks-frame > .page-section-content {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.clocks-frame .page-section-children-box {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.clocks-frame-group {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.clocks-frame-group .frame {
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
mod adjustment_group;
|
||||
mod adjustment_row;
|
||||
|
||||
use crate::{
|
||||
APP_BROKER, I18N,
|
||||
app::{msg::AppMsg, page_section::PageSection},
|
||||
app::{
|
||||
msg::AppMsg, page_section::PageSection,
|
||||
pages::oc_page::clocks_frame::adjustment_group::AdjustmentGroup,
|
||||
},
|
||||
};
|
||||
use adjustment_row::{ClockAdjustmentRow, ClockAdjustmentRowMsg, ClocksData};
|
||||
use adjustment_group::ClockCategory;
|
||||
use adjustment_row::ClocksData;
|
||||
use amdgpu_sysfs::gpu_handle::overdrive::ClocksTableGen as AmdClocksTable;
|
||||
use gtk::{
|
||||
glib::object::ObjectExt,
|
||||
@@ -21,11 +26,11 @@ use relm4::{
|
||||
factory::FactoryHashMap,
|
||||
};
|
||||
|
||||
// This should not end up being used in practice
|
||||
const DEFAULT_VOLTAGE_OFFSET_RANGE: i32 = 250;
|
||||
|
||||
pub struct ClocksFrame {
|
||||
clocks: FactoryHashMap<ClockspeedType, ClockAdjustmentRow>,
|
||||
core_groups: FactoryHashMap<ClockCategory, AdjustmentGroup>,
|
||||
vram_groups: FactoryHashMap<ClockCategory, AdjustmentGroup>,
|
||||
vram_clock_ratio: f64,
|
||||
show_nvidia_options: bool,
|
||||
show_all_pstates: BoolBinding,
|
||||
@@ -49,43 +54,17 @@ impl relm4::Component for ClocksFrame {
|
||||
|
||||
view! {
|
||||
PageSection::new(&fl!(I18N, "overclock-section")) {
|
||||
append_header = >k::Button {
|
||||
set_label: &fl!(I18N, "reset-button"),
|
||||
set_tooltip_text: Some(&fl!(I18N, "reset-oc-tooltip")),
|
||||
add_css_class: "clocks-frame",
|
||||
|
||||
set_halign: gtk::Align::End,
|
||||
append_header = >k::Box {
|
||||
set_spacing: 10,
|
||||
set_hexpand: true,
|
||||
add_css_class: css::DESTRUCTIVE_ACTION,
|
||||
|
||||
#[watch]
|
||||
set_visible: !model.clocks.is_empty(),
|
||||
|
||||
connect_clicked => move |_| {
|
||||
APP_BROKER.send(AppMsg::ResetClocks);
|
||||
}
|
||||
},
|
||||
append_child = >k::Label {
|
||||
set_label: &fl!(I18N, "oc-warning"),
|
||||
set_wrap_mode: pango::WrapMode::Word,
|
||||
set_halign: gtk::Align::Start,
|
||||
set_margin_horizontal: 5,
|
||||
add_css_class: css::WARNING,
|
||||
},
|
||||
|
||||
append_child = >k::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_halign: gtk::Align::Start,
|
||||
set_spacing: 5,
|
||||
#[watch]
|
||||
set_visible: model.show_nvidia_options,
|
||||
|
||||
append = >k::Label {
|
||||
set_label: &fl!(I18N, "nvidia-oc-info"),
|
||||
add_css_class: css::HEADING,
|
||||
},
|
||||
set_halign: gtk::Align::End,
|
||||
|
||||
append = >k::MenuButton {
|
||||
set_icon_name: "dialog-information-symbolic",
|
||||
#[watch]
|
||||
set_visible: model.show_nvidia_options,
|
||||
set_label: &fl!(I18N, "nvidia-oc-info"),
|
||||
|
||||
#[wrap(Some)]
|
||||
set_popover = >k::Popover {
|
||||
@@ -97,6 +76,28 @@ impl relm4::Component for ClocksFrame {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
append = >k::Button {
|
||||
set_label: &fl!(I18N, "reset-button"),
|
||||
set_tooltip_text: Some(&fl!(I18N, "reset-oc-tooltip")),
|
||||
|
||||
add_css_class: css::DESTRUCTIVE_ACTION,
|
||||
|
||||
#[watch]
|
||||
set_visible: model.has_any_clocks(),
|
||||
|
||||
connect_clicked => move |_| {
|
||||
APP_BROKER.send(AppMsg::ResetClocks);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
append_child = >k::Label {
|
||||
set_label: &fl!(I18N, "oc-warning"),
|
||||
set_wrap_mode: pango::WrapMode::Word,
|
||||
set_halign: gtk::Align::Start,
|
||||
add_css_class: css::WARNING,
|
||||
add_css_class: css::DIM_LABEL,
|
||||
},
|
||||
|
||||
append_child = >k::Box {
|
||||
@@ -110,7 +111,8 @@ impl relm4::Component for ClocksFrame {
|
||||
|
||||
append = >k::CheckButton {
|
||||
#[watch]
|
||||
set_visible: model.clocks.values().any(|row| row.is_secondary),
|
||||
set_visible: model.any_is_secondary(),
|
||||
|
||||
set_label: Some(&fl!(I18N, "show-all-pstates")),
|
||||
add_binding["active"]: &model.show_all_pstates,
|
||||
},
|
||||
@@ -139,7 +141,6 @@ impl relm4::Component for ClocksFrame {
|
||||
append = >k::Label {
|
||||
#[watch]
|
||||
set_visible: model.show_all_pstates.value() && model.show_nvidia_options,
|
||||
// add_binding["visible"]: &model.show_all_pstates,
|
||||
|
||||
set_margin_horizontal: 5,
|
||||
set_markup: &fl!(I18N, "pstate-list-description"),
|
||||
@@ -148,10 +149,46 @@ impl relm4::Component for ClocksFrame {
|
||||
},
|
||||
},
|
||||
|
||||
append_child = model.clocks.widget() {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_spacing: 5,
|
||||
set_margin_horizontal: 5,
|
||||
append_child = >k::FlowBox {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_selection_mode: gtk::SelectionMode::None,
|
||||
#[watch]
|
||||
set_max_children_per_line: if model.core_any_visible() && model.vram_any_visible() { 2 } else { 1 },
|
||||
set_column_spacing: 10,
|
||||
set_row_spacing: 10,
|
||||
set_homogeneous: false,
|
||||
set_valign: gtk::Align::Start,
|
||||
set_hexpand: true,
|
||||
|
||||
append = >k::FlowBoxChild {
|
||||
add_css_class: "clocks-frame-group",
|
||||
set_valign: gtk::Align::Start,
|
||||
#[watch]
|
||||
set_visible: model.core_any_visible(),
|
||||
|
||||
#[local_ref]
|
||||
core_groups_widget -> gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_valign: gtk::Align::Start,
|
||||
set_spacing: 10,
|
||||
set_hexpand: true,
|
||||
},
|
||||
},
|
||||
|
||||
append = >k::FlowBoxChild {
|
||||
add_css_class: "clocks-frame-group",
|
||||
set_valign: gtk::Align::Start,
|
||||
#[watch]
|
||||
set_visible: model.vram_any_visible(),
|
||||
|
||||
#[local_ref]
|
||||
vram_groups_widget -> gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_valign: gtk::Align::Start,
|
||||
set_spacing: 10,
|
||||
set_hexpand: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
append_child = >k::Label {
|
||||
@@ -159,7 +196,7 @@ impl relm4::Component for ClocksFrame {
|
||||
set_margin_horizontal: 10,
|
||||
set_halign: gtk::Align::Start,
|
||||
#[watch]
|
||||
set_visible: model.clocks.is_empty(),
|
||||
set_visible: !model.has_any_clocks(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -169,10 +206,9 @@ impl relm4::Component for ClocksFrame {
|
||||
root: Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
let clocks = FactoryHashMap::builder().launch_default().detach();
|
||||
|
||||
let model = Self {
|
||||
clocks,
|
||||
core_groups: FactoryHashMap::builder().launch_default().detach(),
|
||||
vram_groups: FactoryHashMap::builder().launch_default().detach(),
|
||||
vram_clock_ratio: 1.0,
|
||||
show_nvidia_options: false,
|
||||
show_all_pstates: BoolBinding::new(false),
|
||||
@@ -191,6 +227,9 @@ impl relm4::Component for ClocksFrame {
|
||||
});
|
||||
}
|
||||
|
||||
let core_groups_widget = model.core_groups.widget();
|
||||
let vram_groups_widget = model.vram_groups.widget();
|
||||
|
||||
let widgets = view_output!();
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
@@ -212,7 +251,9 @@ impl relm4::Component for ClocksFrame {
|
||||
.vram_locked_clocks_togglebutton
|
||||
.block_signal(&widgets.vram_locked_clock_signal);
|
||||
|
||||
self.clocks.clear();
|
||||
self.core_groups.clear();
|
||||
self.vram_groups.clear();
|
||||
|
||||
self.enable_gpu_locked_clocks.set_value(false);
|
||||
self.enable_vram_locked_clocks.set_value(false);
|
||||
self.show_nvidia_options = false;
|
||||
@@ -225,18 +266,11 @@ impl relm4::Component for ClocksFrame {
|
||||
}
|
||||
}
|
||||
|
||||
// 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(),
|
||||
},
|
||||
);
|
||||
for group in self.all_groups() {
|
||||
group.add_size_group(label_size_group.clone(), input_size_group.clone());
|
||||
}
|
||||
|
||||
widgets
|
||||
@@ -252,25 +286,13 @@ impl relm4::Component for ClocksFrame {
|
||||
self.vram_clock_ratio = vram_ratio;
|
||||
}
|
||||
ClocksFrameMsg::TogglePStatesVisibility => {
|
||||
let show_secondary = self.show_all_pstates.value();
|
||||
for (key, row) in self.clocks.iter() {
|
||||
// Only show min/max core/vram clock when nvidia locked clocks are enabeld
|
||||
let show_current = match key {
|
||||
ClockspeedType::MaxCoreClock | ClockspeedType::MinCoreClock
|
||||
if self.show_nvidia_options =>
|
||||
{
|
||||
self.enable_gpu_locked_clocks.value()
|
||||
}
|
||||
ClockspeedType::MaxMemoryClock | ClockspeedType::MinMemoryClock
|
||||
if self.show_nvidia_options =>
|
||||
{
|
||||
self.enable_vram_locked_clocks.value()
|
||||
}
|
||||
_ => !row.is_secondary || show_secondary,
|
||||
};
|
||||
|
||||
self.clocks
|
||||
.send(key, ClockAdjustmentRowMsg::SetVisible(show_current));
|
||||
for group in self.all_groups() {
|
||||
group.toggle_secondary_visibility(
|
||||
self.show_all_pstates.value(),
|
||||
self.show_nvidia_options,
|
||||
self.enable_gpu_locked_clocks.value(),
|
||||
self.enable_vram_locked_clocks.value(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,17 +303,50 @@ impl relm4::Component for ClocksFrame {
|
||||
}
|
||||
|
||||
impl ClocksFrame {
|
||||
fn set_clock(&mut self, clock_type: ClockspeedType, data: ClocksData) {
|
||||
let category = ClockCategory::from_type(clock_type);
|
||||
|
||||
let groups = if category.is_core() {
|
||||
&mut self.core_groups
|
||||
} else if category.is_vram() {
|
||||
&mut self.vram_groups
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let mut group = if let Some(group) = groups.get_mut(&category) {
|
||||
group
|
||||
} else {
|
||||
groups.insert(category, ());
|
||||
groups.get_mut(&category).unwrap()
|
||||
};
|
||||
|
||||
group.set_clock(clock_type, data);
|
||||
}
|
||||
|
||||
fn all_groups(&self) -> impl Iterator<Item = &AdjustmentGroup> {
|
||||
self.core_groups.values().chain(self.vram_groups.values())
|
||||
}
|
||||
|
||||
fn has_any_clocks(&self) -> bool {
|
||||
self.core_groups.values().any(|group| !group.is_empty())
|
||||
}
|
||||
|
||||
fn any_is_secondary(&self) -> bool {
|
||||
self.all_groups().any(|group| group.has_secondary())
|
||||
}
|
||||
|
||||
fn core_any_visible(&self) -> bool {
|
||||
self.core_groups.values().any(|group| !group.is_empty())
|
||||
}
|
||||
|
||||
fn vram_any_visible(&self) -> bool {
|
||||
self.vram_groups.values().any(|group| !group.is_empty())
|
||||
}
|
||||
|
||||
fn update_vram_clock_ratio(&self) {
|
||||
for clock_type in [
|
||||
ClockspeedType::MaxMemoryClock,
|
||||
ClockspeedType::MinMemoryClock,
|
||||
] {
|
||||
if self.clocks.get(&clock_type).is_some() {
|
||||
self.clocks.send(
|
||||
&clock_type,
|
||||
ClockAdjustmentRowMsg::ValueRatio(self.vram_clock_ratio),
|
||||
);
|
||||
}
|
||||
if let Some(vram_group) = self.vram_groups.get(&ClockCategory::VramClock) {
|
||||
vram_group.set_value_ratio(self.vram_clock_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +361,6 @@ impl ClocksFrame {
|
||||
ClockspeedType::GpuVfCurveClock,
|
||||
min_sclk,
|
||||
max_sclk,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -318,7 +372,6 @@ impl ClocksFrame {
|
||||
ClockspeedType::MemVfCurveClock,
|
||||
min_mclk,
|
||||
max_mclk,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -328,7 +381,6 @@ impl ClocksFrame {
|
||||
ClockspeedType::GpuVfCurveVoltage,
|
||||
min_vddc,
|
||||
max_vddc,
|
||||
false,
|
||||
);
|
||||
|
||||
self.add_amd_list(
|
||||
@@ -336,7 +388,6 @@ impl ClocksFrame {
|
||||
ClockspeedType::MemVfCurveVoltage,
|
||||
min_vddc,
|
||||
max_vddc,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -348,7 +399,7 @@ impl ClocksFrame {
|
||||
.and_then(|range| range.into_full())
|
||||
&& let Some(sclk_offset) = table.sclk_offset
|
||||
{
|
||||
self.clocks.insert(
|
||||
self.set_clock(
|
||||
ClockspeedType::GpuClockOffset(0),
|
||||
ClocksData {
|
||||
current: sclk_offset,
|
||||
@@ -356,7 +407,6 @@ impl ClocksFrame {
|
||||
max: sclk_offset_max,
|
||||
custom_title: Some(fl!(I18N, "gpu-clock-offset")),
|
||||
is_secondary: false,
|
||||
show_separator: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -370,13 +420,11 @@ impl ClocksFrame {
|
||||
ClockspeedType::MaxCoreClock,
|
||||
table.current_sclk_range.max,
|
||||
table.od_range.sclk,
|
||||
false,
|
||||
),
|
||||
(
|
||||
ClockspeedType::MinCoreClock,
|
||||
table.current_sclk_range.min,
|
||||
table.od_range.sclk,
|
||||
false,
|
||||
),
|
||||
]);
|
||||
} else {
|
||||
@@ -389,7 +437,7 @@ impl ClocksFrame {
|
||||
.or(table.od_range.sclk.as_ref())
|
||||
.and_then(|range| range.into_full())
|
||||
{
|
||||
self.clocks.insert(
|
||||
self.set_clock(
|
||||
ClockspeedType::GpuVfCurveClock(i as u8),
|
||||
ClocksData {
|
||||
current: level.clockspeed,
|
||||
@@ -397,7 +445,6 @@ impl ClocksFrame {
|
||||
max: max_sclk,
|
||||
is_secondary: false,
|
||||
custom_title: None,
|
||||
show_separator: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -410,7 +457,7 @@ impl ClocksFrame {
|
||||
.get(i)
|
||||
.and_then(|range| range.into_full())
|
||||
{
|
||||
self.clocks.insert(
|
||||
self.set_clock(
|
||||
ClockspeedType::GpuVfCurveVoltage(i as u8),
|
||||
ClocksData {
|
||||
current: level.voltage,
|
||||
@@ -418,7 +465,6 @@ impl ClocksFrame {
|
||||
max: max_vddc,
|
||||
is_secondary: false,
|
||||
custom_title: None,
|
||||
show_separator: i == table.vddc_curve.len() - 1, // Show on first row (reversed count)
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -430,26 +476,19 @@ impl ClocksFrame {
|
||||
ClockspeedType::MaxMemoryClock,
|
||||
table.current_mclk_range.max,
|
||||
table.od_range.mclk,
|
||||
true,
|
||||
),
|
||||
(
|
||||
ClockspeedType::MinMemoryClock,
|
||||
table.current_mclk_range.min,
|
||||
table.od_range.mclk,
|
||||
false,
|
||||
),
|
||||
]);
|
||||
|
||||
for (clockspeed_type, current_value, range, show_separator) in clocks_types {
|
||||
for (clockspeed_type, current_value, range) in clocks_types {
|
||||
if let Some(current) = current_value
|
||||
&& let Some((min, max)) = range.and_then(|range| range.into_full())
|
||||
{
|
||||
let mut data = ClocksData::new(current, min, max);
|
||||
if show_separator && !self.clocks.is_empty() {
|
||||
data.show_separator = true;
|
||||
}
|
||||
|
||||
self.clocks.insert(clockspeed_type, data);
|
||||
self.set_clock(clockspeed_type, ClocksData::new(current, min, max));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,9 +499,10 @@ impl ClocksFrame {
|
||||
.and_then(|range| range.into_full())
|
||||
.unwrap_or((-DEFAULT_VOLTAGE_OFFSET_RANGE, DEFAULT_VOLTAGE_OFFSET_RANGE));
|
||||
|
||||
let mut data = ClocksData::new(current, min, max);
|
||||
data.show_separator = true;
|
||||
self.clocks.insert(ClockspeedType::VoltageOffset, data);
|
||||
self.set_clock(
|
||||
ClockspeedType::VoltageOffset,
|
||||
ClocksData::new(current, min, max),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -474,13 +514,12 @@ impl ClocksFrame {
|
||||
clock_type: fn(u8) -> ClockspeedType,
|
||||
min: i32,
|
||||
max: i32,
|
||||
disable_separator: bool,
|
||||
) {
|
||||
let values_len = values.len();
|
||||
for (i, value) in values.enumerate().rev() {
|
||||
let is_secondary = i > 0 && i < values_len - 1;
|
||||
|
||||
self.clocks.insert(
|
||||
self.set_clock(
|
||||
clock_type(i as u8),
|
||||
ClocksData {
|
||||
current: value,
|
||||
@@ -488,7 +527,6 @@ impl ClocksFrame {
|
||||
max,
|
||||
is_secondary,
|
||||
custom_title: None,
|
||||
show_separator: !disable_separator && i == values_len - 1, // Show on first row (reversed count)
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -503,14 +541,14 @@ impl ClocksFrame {
|
||||
table.gpu_locked_clocks,
|
||||
ClockspeedType::MinCoreClock,
|
||||
ClockspeedType::MaxCoreClock,
|
||||
&self.enable_gpu_locked_clocks,
|
||||
self.enable_gpu_locked_clocks.clone(),
|
||||
),
|
||||
(
|
||||
table.vram_clock_range,
|
||||
table.vram_locked_clocks,
|
||||
ClockspeedType::MinMemoryClock,
|
||||
ClockspeedType::MaxMemoryClock,
|
||||
&self.enable_vram_locked_clocks,
|
||||
self.enable_vram_locked_clocks.clone(),
|
||||
),
|
||||
];
|
||||
|
||||
@@ -524,11 +562,11 @@ impl ClocksFrame {
|
||||
None => (gpu_min, gpu_max),
|
||||
};
|
||||
|
||||
self.clocks.insert(
|
||||
self.set_clock(
|
||||
min_type,
|
||||
ClocksData::new(current_min as i32, gpu_min as i32, gpu_max as i32),
|
||||
);
|
||||
self.clocks.insert(
|
||||
self.set_clock(
|
||||
max_type,
|
||||
ClocksData::new(current_max as i32, gpu_min as i32, gpu_max as i32),
|
||||
);
|
||||
@@ -536,13 +574,13 @@ impl ClocksFrame {
|
||||
}
|
||||
|
||||
for (pstate, offset) in table.gpu_offsets {
|
||||
self.clocks.insert(
|
||||
self.set_clock(
|
||||
ClockspeedType::GpuClockOffset(pstate),
|
||||
nvidia_clock_offset_to_data(&offset, pstate > 0),
|
||||
);
|
||||
}
|
||||
for (pstate, offset) in table.mem_offsets {
|
||||
self.clocks.insert(
|
||||
self.set_clock(
|
||||
ClockspeedType::MemClockOffset(pstate),
|
||||
nvidia_clock_offset_to_data(&offset, pstate > 0),
|
||||
);
|
||||
@@ -555,11 +593,11 @@ impl ClocksFrame {
|
||||
if let Some((current_gt_min, current_gt_max)) = table.gt_freq
|
||||
&& let (Some(min_clock), Some(max_clock)) = (table.rpn_freq, table.rp0_freq)
|
||||
{
|
||||
self.clocks.insert(
|
||||
self.set_clock(
|
||||
ClockspeedType::MaxCoreClock,
|
||||
ClocksData::new(current_gt_max as i32, min_clock as i32, max_clock as i32),
|
||||
);
|
||||
self.clocks.insert(
|
||||
self.set_clock(
|
||||
ClockspeedType::MinCoreClock,
|
||||
ClocksData::new(current_gt_min as i32, min_clock as i32, max_clock as i32),
|
||||
);
|
||||
@@ -567,30 +605,39 @@ impl ClocksFrame {
|
||||
}
|
||||
|
||||
pub fn get_commands(&self) -> Vec<SetClocksCommand> {
|
||||
self.clocks
|
||||
.iter()
|
||||
.filter_map(|(clock_type, row)| {
|
||||
// If nvidia options are enabled, we always set locked clocks to None or Some
|
||||
self.all_groups()
|
||||
.flat_map(|group| group.get_commands())
|
||||
.map(|(clock_type, configured_value)| {
|
||||
let value = if self.show_nvidia_options {
|
||||
match clock_type {
|
||||
ClockspeedType::MinCoreClock | ClockspeedType::MaxCoreClock => self
|
||||
.enable_gpu_locked_clocks
|
||||
.value()
|
||||
.then(|| row.get_raw_value()),
|
||||
.then(|| {
|
||||
self.core_groups
|
||||
.get(&ClockCategory::from_type(clock_type))
|
||||
.map(|group| group.get_raw_value(clock_type))
|
||||
})
|
||||
.flatten(),
|
||||
ClockspeedType::MinMemoryClock | ClockspeedType::MaxMemoryClock => self
|
||||
.enable_vram_locked_clocks
|
||||
.value()
|
||||
.then(|| row.get_raw_value()),
|
||||
_ => Some(row.get_configured_value()?),
|
||||
.then(|| {
|
||||
self.vram_groups
|
||||
.get(&ClockCategory::from_type(clock_type))
|
||||
.map(|group| group.get_raw_value(clock_type))
|
||||
})
|
||||
.flatten(),
|
||||
_ => configured_value,
|
||||
}
|
||||
} else {
|
||||
Some(row.get_configured_value()?)
|
||||
configured_value
|
||||
};
|
||||
|
||||
Some(SetClocksCommand {
|
||||
r#type: *clock_type,
|
||||
SetClocksCommand {
|
||||
r#type: clock_type,
|
||||
value,
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@@ -603,6 +650,5 @@ fn nvidia_clock_offset_to_data(clock_info: &NvidiaClockOffset, is_secondary: boo
|
||||
max: clock_info.max,
|
||||
custom_title: None,
|
||||
is_secondary,
|
||||
show_separator: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
use super::adjustment_row::{ClockAdjustmentRow, ClockAdjustmentRowMsg, ClocksData};
|
||||
use gtk::prelude::{BoxExt, OrientableExt, WidgetExt};
|
||||
use lact_schema::request::ClockspeedType;
|
||||
use relm4::{css, factory::FactoryHashMap, prelude::FactoryComponent};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ClockCategory {
|
||||
CoreClock,
|
||||
CoreVoltage,
|
||||
VramClock,
|
||||
CoreCurveClock,
|
||||
VramCurveClock,
|
||||
CoreCurveVoltage,
|
||||
VramCurveVoltage,
|
||||
}
|
||||
|
||||
impl ClockCategory {
|
||||
pub fn from_type(clock_type: ClockspeedType) -> Self {
|
||||
match clock_type {
|
||||
ClockspeedType::MaxCoreClock
|
||||
| ClockspeedType::MinCoreClock
|
||||
| ClockspeedType::GpuClockOffset(_) => ClockCategory::CoreClock,
|
||||
ClockspeedType::MinVoltage
|
||||
| ClockspeedType::MaxVoltage
|
||||
| ClockspeedType::VoltageOffset => ClockCategory::CoreVoltage,
|
||||
ClockspeedType::MaxMemoryClock
|
||||
| ClockspeedType::MinMemoryClock
|
||||
| ClockspeedType::MemClockOffset(_) => ClockCategory::VramClock,
|
||||
ClockspeedType::GpuVfCurveClock(_) => ClockCategory::CoreCurveClock,
|
||||
ClockspeedType::MemVfCurveClock(_) => ClockCategory::VramCurveClock,
|
||||
ClockspeedType::GpuVfCurveVoltage(_) => ClockCategory::CoreCurveVoltage,
|
||||
ClockspeedType::MemVfCurveVoltage(_) => ClockCategory::VramCurveVoltage,
|
||||
ClockspeedType::Reset => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_core(&self) -> bool {
|
||||
Self::CORE.contains(self)
|
||||
}
|
||||
|
||||
pub fn is_vram(&self) -> bool {
|
||||
Self::VRAM.contains(self)
|
||||
}
|
||||
|
||||
pub const CORE: [ClockCategory; 4] = [
|
||||
ClockCategory::CoreClock,
|
||||
ClockCategory::CoreVoltage,
|
||||
ClockCategory::CoreCurveClock,
|
||||
ClockCategory::CoreCurveVoltage,
|
||||
];
|
||||
|
||||
pub const VRAM: [ClockCategory; 3] = [
|
||||
ClockCategory::VramClock,
|
||||
ClockCategory::VramCurveClock,
|
||||
ClockCategory::VramCurveVoltage,
|
||||
];
|
||||
}
|
||||
|
||||
pub struct AdjustmentGroup {
|
||||
adjustments: FactoryHashMap<ClockspeedType, ClockAdjustmentRow>,
|
||||
}
|
||||
|
||||
impl AdjustmentGroup {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.adjustments.is_empty()
|
||||
}
|
||||
|
||||
pub fn has_secondary(&self) -> bool {
|
||||
self.adjustments.values().any(|row| row.is_secondary)
|
||||
}
|
||||
|
||||
pub fn set_clock(&mut self, clock_type: ClockspeedType, data: ClocksData) {
|
||||
self.adjustments.insert(clock_type, data);
|
||||
}
|
||||
|
||||
pub fn add_size_group(&self, label_group: gtk::SizeGroup, input_group: gtk::SizeGroup) {
|
||||
for clock_type in self.adjustments.keys() {
|
||||
self.adjustments.send(
|
||||
clock_type,
|
||||
ClockAdjustmentRowMsg::AddSizeGroup {
|
||||
label_group: label_group.clone(),
|
||||
input_group: input_group.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_value_ratio(&self, ratio: f64) {
|
||||
for clock_type in self.adjustments.keys() {
|
||||
self.adjustments
|
||||
.send(clock_type, ClockAdjustmentRowMsg::ValueRatio(ratio));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_secondary_visibility(
|
||||
&self,
|
||||
show_secondary: bool,
|
||||
show_nvidia_options: bool,
|
||||
enable_gpu_locked: bool,
|
||||
enable_vram_locked: bool,
|
||||
) {
|
||||
for (key, row) in self.adjustments.iter() {
|
||||
let show_current = match key {
|
||||
ClockspeedType::MaxCoreClock | ClockspeedType::MinCoreClock
|
||||
if show_nvidia_options =>
|
||||
{
|
||||
enable_gpu_locked
|
||||
}
|
||||
ClockspeedType::MaxMemoryClock | ClockspeedType::MinMemoryClock
|
||||
if show_nvidia_options =>
|
||||
{
|
||||
enable_vram_locked
|
||||
}
|
||||
_ => !row.is_secondary || show_secondary,
|
||||
};
|
||||
|
||||
self.adjustments
|
||||
.send(key, ClockAdjustmentRowMsg::SetVisible(show_current));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_commands(&self) -> Vec<(ClockspeedType, Option<i32>)> {
|
||||
self.adjustments
|
||||
.iter()
|
||||
.map(|(clock_type, row)| (*clock_type, row.get_configured_value()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_raw_value(&self, clock_type: ClockspeedType) -> i32 {
|
||||
self.adjustments
|
||||
.get(&clock_type)
|
||||
.map(|row| row.get_raw_value())
|
||||
.unwrap_or(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[relm4::factory(pub)]
|
||||
impl FactoryComponent for AdjustmentGroup {
|
||||
type Init = ();
|
||||
type Input = ();
|
||||
type Output = ();
|
||||
type CommandOutput = ();
|
||||
type ParentWidget = gtk::Box;
|
||||
type Index = ClockCategory;
|
||||
|
||||
view! {
|
||||
self.adjustments.widget().clone() -> gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_spacing: 5,
|
||||
set_valign: gtk::Align::Start,
|
||||
add_css_class: css::FRAME,
|
||||
}
|
||||
}
|
||||
|
||||
fn init_model(_: Self::Init, _: &Self::Index, _: relm4::FactorySender<Self>) -> Self {
|
||||
Self {
|
||||
adjustments: FactoryHashMap::builder().launch_default().detach(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ use crate::{
|
||||
APP_BROKER, I18N,
|
||||
app::{msg::AppMsg, pages::oc_adjustment::OcAdjustment},
|
||||
};
|
||||
use gtk::prelude::BoxExt;
|
||||
use gtk::{
|
||||
glib::{
|
||||
SignalHandlerId,
|
||||
@@ -12,7 +13,7 @@ use gtk::{
|
||||
};
|
||||
use i18n_embed_fl::fl;
|
||||
use lact_schema::request::ClockspeedType;
|
||||
use relm4::{RelmWidgetExt, prelude::FactoryComponent};
|
||||
use relm4::prelude::FactoryComponent;
|
||||
|
||||
pub struct ClockAdjustmentRow {
|
||||
clock_type: ClockspeedType,
|
||||
@@ -20,7 +21,6 @@ pub struct ClockAdjustmentRow {
|
||||
value_ratio: f64,
|
||||
change_signal: SignalHandlerId,
|
||||
adjustment: OcAdjustment,
|
||||
show_separator: bool,
|
||||
pub(super) is_secondary: bool,
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ pub struct ClocksData {
|
||||
pub max: i32,
|
||||
pub custom_title: Option<String>,
|
||||
pub is_secondary: bool,
|
||||
pub show_separator: bool,
|
||||
}
|
||||
|
||||
impl ClocksData {
|
||||
@@ -41,46 +40,10 @@ impl ClocksData {
|
||||
max,
|
||||
is_secondary: false,
|
||||
custom_title: None,
|
||||
show_separator: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn make_event_controller_no_scroll() -> gtk::EventControllerScroll {
|
||||
let controller = gtk::EventControllerScroll::new(
|
||||
gtk::EventControllerScrollFlags::VERTICAL | gtk::EventControllerScrollFlags::HORIZONTAL,
|
||||
);
|
||||
controller.connect_scroll(|controller, dx, dy| {
|
||||
if let Some(parent) = controller
|
||||
.widget()
|
||||
.and_then(|widget| widget.ancestor(gtk::ScrolledWindow::static_type()))
|
||||
{
|
||||
let scrolled_window = parent.downcast::<gtk::ScrolledWindow>().unwrap();
|
||||
|
||||
if dy != 0.0 {
|
||||
let current = scrolled_window.vadjustment().value();
|
||||
let step = scrolled_window.vadjustment().step_increment();
|
||||
|
||||
// This is a bit of a hack, fractional values are generally touchpad inputs (in pixels),
|
||||
// while whole values are scroll wheel events (which should use the `step` value)
|
||||
// With newer GTK this should be changed to getting `unit()` from the scroll controller
|
||||
let delta = if dy.fract() == 0.0 { dy * step } else { dy };
|
||||
scrolled_window.vadjustment().set_value(current + delta);
|
||||
}
|
||||
|
||||
if dx != 0.0 {
|
||||
let current = scrolled_window.hadjustment().value();
|
||||
let step = scrolled_window.hadjustment().step_increment();
|
||||
let delta = if dx.fract() == 0.0 { dy * step } else { dy };
|
||||
scrolled_window.hadjustment().set_value(current + delta);
|
||||
}
|
||||
}
|
||||
|
||||
gtk::glib::Propagation::Stop
|
||||
});
|
||||
controller
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ClockAdjustmentRowMsg {
|
||||
ValueRatio(f64),
|
||||
@@ -105,14 +68,10 @@ impl FactoryComponent for ClockAdjustmentRow {
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
|
||||
gtk::Separator {
|
||||
set_visible: self.show_separator,
|
||||
set_margin_top: 5,
|
||||
set_margin_bottom: 10,
|
||||
},
|
||||
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_spacing: 5,
|
||||
|
||||
#[name = "title_label"]
|
||||
gtk::Label {
|
||||
set_xalign: 0.0,
|
||||
@@ -147,7 +106,7 @@ impl FactoryComponent for ClockAdjustmentRow {
|
||||
set_digits: 0,
|
||||
set_round_digits: 0,
|
||||
set_value_pos: gtk::PositionType::Right,
|
||||
set_margin_horizontal: 5,
|
||||
set_width_request: 150,
|
||||
add_controller = make_event_controller_no_scroll(),
|
||||
},
|
||||
|
||||
@@ -184,7 +143,6 @@ impl FactoryComponent for ClockAdjustmentRow {
|
||||
change_signal,
|
||||
value_ratio: 1.0,
|
||||
is_secondary: data.is_secondary,
|
||||
show_separator: data.show_separator,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -237,3 +195,38 @@ impl ClockAdjustmentRow {
|
||||
(self.adjustment.value() / self.value_ratio) as i32
|
||||
}
|
||||
}
|
||||
|
||||
fn make_event_controller_no_scroll() -> gtk::EventControllerScroll {
|
||||
let controller = gtk::EventControllerScroll::new(
|
||||
gtk::EventControllerScrollFlags::VERTICAL | gtk::EventControllerScrollFlags::HORIZONTAL,
|
||||
);
|
||||
controller.connect_scroll(|controller, dx, dy| {
|
||||
if let Some(parent) = controller
|
||||
.widget()
|
||||
.and_then(|widget| widget.ancestor(gtk::ScrolledWindow::static_type()))
|
||||
{
|
||||
let scrolled_window = parent.downcast::<gtk::ScrolledWindow>().unwrap();
|
||||
|
||||
if dy != 0.0 {
|
||||
let current = scrolled_window.vadjustment().value();
|
||||
let step = scrolled_window.vadjustment().step_increment();
|
||||
|
||||
// This is a bit of a hack, fractional values are generally touchpad inputs (in pixels),
|
||||
// while whole values are scroll wheel events (which should use the `step` value)
|
||||
// With newer GTK this should be changed to getting `unit()` from the scroll controller
|
||||
let delta = if dy.fract() == 0.0 { dy * step } else { dy };
|
||||
scrolled_window.vadjustment().set_value(current + delta);
|
||||
}
|
||||
|
||||
if dx != 0.0 {
|
||||
let current = scrolled_window.hadjustment().value();
|
||||
let step = scrolled_window.hadjustment().step_increment();
|
||||
let delta = if dx.fract() == 0.0 { dy * step } else { dy };
|
||||
scrolled_window.hadjustment().set_value(current + delta);
|
||||
}
|
||||
}
|
||||
|
||||
gtk::glib::Propagation::Stop
|
||||
});
|
||||
controller
|
||||
}
|
||||
|
||||
@@ -137,18 +137,23 @@ impl SetClocksCommand {
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ClockspeedType {
|
||||
MaxCoreClock,
|
||||
MaxMemoryClock,
|
||||
MaxVoltage,
|
||||
MinCoreClock,
|
||||
MinMemoryClock,
|
||||
MinVoltage,
|
||||
VoltageOffset,
|
||||
GpuClockOffset(u32),
|
||||
|
||||
MinVoltage,
|
||||
MaxVoltage,
|
||||
VoltageOffset,
|
||||
|
||||
MaxMemoryClock,
|
||||
MinMemoryClock,
|
||||
MemClockOffset(u32),
|
||||
|
||||
GpuVfCurveClock(u8),
|
||||
MemVfCurveClock(u8),
|
||||
GpuVfCurveVoltage(u8),
|
||||
|
||||
MemVfCurveClock(u8),
|
||||
MemVfCurveVoltage(u8),
|
||||
|
||||
Reset,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user