use amdgpu::pidfile::helper_cmd::{send_command, Command, Response};
use amdgpu_config::fan::TempPoint;
use egui::{emath, pos2, Color32, Layout, PointerButton, Ui};
use crate::app::{ChangeState, FanConfig, FanServices, StatefulConfig};
use crate::widgets;
use crate::widgets::drag_plot::PlotMsg;
use crate::widgets::reload_section::ReloadSection;
use crate::widgets::TempConfigFile;
pub struct EditTempConfig {
config: FanConfig,
selected: Option<usize>,
matrix: Vec<TempPoint>,
}
impl EditTempConfig {
pub fn new(config: FanConfig) -> Self {
let matrix = config.lock().temp_matrix().to_vec();
Self {
matrix,
config,
selected: None,
}
}
pub fn select(&mut self, idx: usize) {
self.selected = Some(idx);
}
pub fn deselect(&mut self) {
self.selected = None;
}
pub fn draw(&mut self, ui: &mut Ui, pid_files: &mut FanServices, state: &mut StatefulConfig) {
let available = ui.available_rect_before_wrap();
ui.horizontal_top(|ui| {
ui.child_ui(
emath::Rect {
min: available.min,
max: pos2(available.width() / 2.0, available.height()),
},
Layout::left_to_right(),
)
.vertical(|ui| {
egui::ScrollArea::vertical()
.enable_scrolling(true)
.id_source("temp-config")
.show(ui, |ui| {
ui.add({
let curve = {
let config = self.config.lock();
let iter = config
.temp_matrix()
.iter()
.map(|v| crate::items::Value::new(v.temp, v.speed));
crate::items::Line::new(crate::items::Values::from_values_iter(
iter,
))
.color(Color32::BLUE)
};
widgets::drag_plot::DragPlot::new("change temp settings")
.height(600.0)
.width(available.width() / 2.0)
.selected(self.selected)
.allow_drag(true)
.allow_zoom(false)
.line(curve)
.y_axis_name("Speed")
.x_axis_name("Temperature")
.hline(crate::items::HLine::new(0.0).color(Color32::BLACK))
.hline(crate::items::HLine::new(100.0).color(Color32::BLACK))
.vline(crate::items::VLine::new(0.0).color(Color32::BLACK))
.vline(crate::items::VLine::new(100.0).color(Color32::BLACK))
.on_event(|msg| match msg {
PlotMsg::Clicked(idx) => {
self.selected = Some(idx);
}
PlotMsg::Drag(delta) => {
if let Some(idx) = self.selected {
let mut config = self.config.lock();
let min = idx
.checked_sub(1)
.and_then(|i| config.temp_matrix().get(i).copied())
.unwrap_or(TempPoint::MIN);
let max = idx
.checked_add(1)
.and_then(|i| config.temp_matrix().get(i).copied())
.unwrap_or(TempPoint::MAX);
let current = config.temp_matrix_mut().get_mut(idx);
if let Some((cache, current)) =
self.matrix.get_mut(idx).zip(current.as_deref())
{
cache.speed = current.speed;
cache.temp = current.temp;
}
if let Some(point) = current {
point.speed = (point.speed + delta.y as f64)
.max(min.speed)
.min(max.speed);
point.temp = (point.temp + delta.x as f64)
.max(min.temp)
.min(max.temp);
}
}
}
})
.legend(widgets::legend::Legend::default())
});
ui.separator();
Self::save_button(self.config.clone(), state, ui);
ui.add(ReloadSection::new(pid_files));
});
});
ui.child_ui(
emath::Rect {
min: pos2(available.width() / 2.0 + 20.0, available.min.y),
max: available.max,
},
Layout::left_to_right(),
)
.vertical(|ui| {
ui.add(TempConfigFile::new(self.config.clone(), &mut self.matrix));
});
});
}
fn save_button(config: FanConfig, state: &mut StatefulConfig, ui: &mut Ui) {
ui.horizontal(|ui| {
if ui.button("Save").clicked_by(PointerButton::Primary) {
Self::save_config(config, state);
}
match &state.state {
ChangeState::New => {}
ChangeState::Reloading => {
ui.label("Saving...");
}
ChangeState::Success => {
ui.add(egui::Label::new("Saved"));
}
ChangeState::Failure(msg) => {
ui.add(egui::Label::new(format!("Failure. {}", msg)));
}
}
});
}
#[allow(clippy::explicit_auto_deref)]
fn save_config(config: FanConfig, state: &mut StatefulConfig) {
state.state = ChangeState::Reloading;
let config = config.lock();
let c: &amdgpu_config::fan::Config = &*config;
let content = match toml::to_string(c) {
Err(e) => {
tracing::error!("Config file serialization failed. {:?}", e);
return;
}
Ok(content) => content,
};
let command = Command::SaveFanConfig {
path: String::from(config.path()),
content,
};
match send_command(command) {
Ok(Response::ConfigFileSaveFailed(msg)) => {
state.state = ChangeState::Failure(msg);
}
Ok(Response::ConfigFileSaved) => {
state.state = ChangeState::Success;
}
_ => {}
}
}
}