Fix clippy

This commit is contained in:
Adrian Woźniak 2022-08-18 14:35:53 +02:00
parent bcf2b9e5f9
commit 8d8f4932c1
No known key found for this signature in database
GPG Key ID: 0012845A89C7352B
18 changed files with 314 additions and 223 deletions

1
Cargo.lock generated
View File

@ -152,6 +152,7 @@ dependencies = [
"egui_glium",
"egui_glow",
"egui_vulkano",
"emath 0.18.0",
"epaint 0.18.1",
"epi",
"glium 0.32.1",

View File

@ -18,18 +18,170 @@ pub enum PortsError {
Serialize(#[from] ron::Error),
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum OutputType {
Reserved,
#[serde(rename = "v")]
Vga,
#[serde(rename = "m")]
MiniDvi,
#[serde(rename = "h")]
Hdmi,
#[serde(rename = "a")]
Audio,
#[serde(rename = "o")]
OpticalAudio,
#[serde(rename = "d")]
Dvi,
#[serde(rename = "t")]
Thunderbolt,
#[serde(rename = "D")]
DisplayPort,
#[serde(rename = "M")]
MiniDisplayPort,
#[serde(rename = "f")]
FireWire400,
#[serde(rename = "p")]
Ps2,
#[serde(rename = "s")]
Sata,
#[serde(rename = "e")]
ESata,
#[serde(rename = "E")]
Ethernet,
#[serde(rename = "F")]
FireWire800,
#[serde(rename = "1")]
UsbTypeA,
#[serde(rename = "2")]
UsbTypeB,
#[serde(rename = "3")]
UsbTypeC,
#[serde(rename = "4")]
MicroUsb,
#[serde(rename = "5")]
MimiUsb,
}
impl OutputType {
pub fn to_coords(&self) -> (u32, u32) {
match self {
OutputType::Reserved => (0, 0),
//
OutputType::Vga => (0, 0),
OutputType::MiniDvi => (80, 0),
OutputType::Hdmi => (160, 0),
OutputType::Audio => (240, 0),
OutputType::OpticalAudio => (320, 0),
//
OutputType::Dvi => (0, 80),
OutputType::Thunderbolt => (80, 80),
OutputType::DisplayPort => (160, 80),
OutputType::MiniDisplayPort => (240, 80),
OutputType::FireWire400 => (320, 80),
//
OutputType::Ps2 => (0, 160),
OutputType::Sata => (80, 160),
OutputType::ESata => (160, 160),
OutputType::Ethernet => (240, 160),
OutputType::FireWire800 => (320, 160),
//
OutputType::UsbTypeA => (0, 240),
OutputType::UsbTypeB => (80, 240),
OutputType::UsbTypeC => (160, 240),
OutputType::MicroUsb => (240, 240),
OutputType::MimiUsb => (320, 240),
}
}
pub fn name(&self) -> &str {
match self {
OutputType::Reserved => "-----",
//
OutputType::Vga => "Vga",
OutputType::MiniDvi => "MiniDvi",
OutputType::Hdmi => "Hdmi",
OutputType::Audio => "Audio",
OutputType::OpticalAudio => "OptimalAudio",
//
OutputType::Dvi => "Dvi",
OutputType::Thunderbolt => "Thunderbolt",
OutputType::DisplayPort => "DisplayPort",
OutputType::MiniDisplayPort => "MiniDisplayPort",
OutputType::FireWire400 => "FireWire400",
//
OutputType::Ps2 => "Ps2",
OutputType::Sata => "Sata",
OutputType::ESata => "ESata",
OutputType::Ethernet => "Ethernet",
OutputType::FireWire800 => "FireWire800",
//
OutputType::UsbTypeA => "UsbTypeA",
OutputType::UsbTypeB => "UsbTypeB",
OutputType::UsbTypeC => "UsbTypeC",
OutputType::MicroUsb => "MicroUsb",
OutputType::MimiUsb => "MimiUsb",
}
}
pub fn parse_str(s: &str) -> Option<Self> {
Some(match s {
"DP" => Self::DisplayPort,
"eDP" => Self::MiniDisplayPort,
"HDMI" => Self::Hdmi,
_ => return None,
})
}
pub fn all() -> [OutputType; 20] {
[
OutputType::Vga,
OutputType::MiniDvi,
OutputType::Hdmi,
OutputType::Audio,
OutputType::OpticalAudio,
OutputType::Dvi,
OutputType::Thunderbolt,
OutputType::DisplayPort,
OutputType::MiniDisplayPort,
OutputType::FireWire400,
OutputType::Ps2,
OutputType::Sata,
OutputType::ESata,
OutputType::Ethernet,
OutputType::FireWire800,
OutputType::UsbTypeA,
OutputType::UsbTypeB,
OutputType::UsbTypeC,
OutputType::MicroUsb,
OutputType::MimiUsb,
]
}
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct Output {
#[serde(rename = "c")]
pub card: String,
#[serde(rename = "t")]
pub port_type: String,
#[serde(rename = "T")]
pub ty: Option<OutputType>,
#[serde(rename = "m")]
pub port_name: Option<String>,
#[serde(rename = "n")]
pub port_number: u8,
#[serde(rename = "s")]
pub status: Status,
#[serde(rename = "M")]
pub modes: Vec<OutputMode>,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct OutputMode {
#[serde(rename = "w")]
pub width: u16,
#[serde(rename = "h")]
pub height: u16,
}
#[derive(Debug, Clone, Serialize, Deserialize)]

View File

@ -65,6 +65,7 @@ parking_lot = { version = "0.12" }
nix = { version = "0.25" }
image = { version = "0.24.2" }
emath = { version = "0.18" }
[dev-dependencies]
amdgpu = { path = "../amdgpu", version = "1.0", features = ["gui-helper"] }

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -1,11 +1,12 @@
use std::collections::{BTreeMap, HashMap};
use std::sync::Arc;
use amdgpu::pidfile::ports::Output;
use amdgpu::pidfile::ports::{Output, OutputType};
use amdgpu::pidfile::Pid;
use egui::Ui;
use epaint::ColorImage;
use epi::Frame;
use image::{ImageBuffer, ImageFormat, RgbaImage};
use image::{GenericImageView, ImageBuffer, ImageFormat};
use parking_lot::Mutex;
use crate::widgets::outputs_settings::OutputsSettings;
@ -83,113 +84,55 @@ static RELOAD_PID_LIST_DELAY: u8 = 18;
#[cfg(debug_assertions)]
static RELOAD_PID_LIST_DELAY: u8 = 80;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum ImageType {
Vga,
MiniDvi,
Hdmi,
Audio,
OptimalAudio,
Dvi,
Thunderbolt,
DisplayPort,
MiniDisplayPort,
FireWire400,
Ps2,
Sata,
ESata,
Ethernet,
FireWire800,
UsbTypeA,
UsbTypeB,
UsbTypeC,
MicroUsb,
MimiUsb,
}
impl ImageType {
pub fn to_coords(&self) -> (u32, u32) {
match self {
ImageType::Vga => (0, 0),
ImageType::MiniDvi => (160, 0),
ImageType::Hdmi => (320, 0),
ImageType::Audio => (480, 0),
ImageType::OptimalAudio => (640, 0),
//
ImageType::Dvi => (0, 160),
ImageType::Thunderbolt => (160, 160),
ImageType::DisplayPort => (320, 160),
ImageType::MiniDisplayPort => (480, 160),
ImageType::FireWire400 => (640, 160),
//
ImageType::Ps2 => (0, 320),
ImageType::Sata => (160, 320),
ImageType::ESata => (320, 320),
ImageType::Ethernet => (480, 320),
ImageType::FireWire800 => (640, 320),
//
ImageType::UsbTypeA => (0, 480),
ImageType::UsbTypeB => (160, 480),
ImageType::UsbTypeC => (320, 480),
ImageType::MicroUsb => (480, 480),
ImageType::MimiUsb => (640, 480),
}
}
}
pub struct StatefulConfig {
pub config: FanConfig,
pub state: ChangeState,
pub images: HashMap<ImageType, RgbaImage>,
pub textures: HashMap<OutputType, epaint::TextureHandle>,
}
impl StatefulConfig {
pub fn new(config: FanConfig) -> Self {
let compact = image::load_from_memory_with_format(
include_bytes!("../assets/icons/ports.jpg"),
ImageFormat::Jpeg,
)
.unwrap()
.into_rgba8();
let images = [
ImageType::Vga,
ImageType::MiniDvi,
ImageType::Hdmi,
ImageType::Audio,
ImageType::OptimalAudio,
ImageType::Dvi,
ImageType::Thunderbolt,
ImageType::DisplayPort,
ImageType::MiniDisplayPort,
ImageType::FireWire400,
ImageType::Ps2,
ImageType::Sata,
ImageType::ESata,
ImageType::Ethernet,
ImageType::FireWire800,
ImageType::UsbTypeA,
ImageType::UsbTypeB,
ImageType::UsbTypeC,
ImageType::MicroUsb,
ImageType::MimiUsb,
]
.iter()
.fold(HashMap::with_capacity(20), |mut memo, ty| {
let (offset_x, offset_y) = ty.to_coords();
let mut part = ImageBuffer::new(160, 160);
for x in 0..160 {
for y in 0..160 {
part.put_pixel(x, y, compact.get_pixel(x + offset_x, y + offset_y).clone());
}
}
memo.insert(*ty, part);
memo
});
let textures = HashMap::with_capacity(40);
Self {
config,
state: ChangeState::New,
images,
textures,
}
}
pub fn load_textures(&mut self, ui: &mut Ui) {
if !self.textures.is_empty() {
return;
}
// 80x80
let image = {
let bytes = include_bytes!("../assets/icons/ports2.jpg");
image::load_from_memory_with_format(bytes, ImageFormat::Jpeg).unwrap()
};
let ctx = ui.ctx();
for ty in OutputType::all() {
let (offset_x, offset_y) = ty.to_coords();
let mut img = ImageBuffer::new(80, 80);
for x in 0..80 {
for y in 0..80 {
img.put_pixel(x, y, image.get_pixel(x + offset_x, y + offset_y));
}
}
let size = [img.width() as _, img.height() as _];
let pixels = img.as_flat_samples();
let id = ctx.load_texture(
String::from(ty.name()),
epaint::ImageData::Color(ColorImage::from_rgba_unmultiplied(
size,
pixels.as_slice(),
)),
);
self.textures.insert(ty, id);
}
}
}
@ -228,6 +171,8 @@ impl AmdGui {
}
pub fn ui(&mut self, ui: &mut Ui) {
self.config.load_textures(ui);
match self.page {
Page::Config => {
self.change_fan_settings
@ -277,7 +222,7 @@ impl AmdGui {
let mut names = outputs.iter().fold(
Vec::with_capacity(outputs.len()),
|mut set, output| {
set.push(format!("{}", output.card));
set.push(output.card.clone());
set
},
);

View File

@ -1,10 +1,13 @@
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;
use glium::glutin;
use image::RgbaImage;
use parking_lot::Mutex;
use tokio::sync::mpsc::UnboundedReceiver;
use crate::app::AmdGui;
use crate::app::{AmdGui, ImageStorage, ImageType};
use crate::backend::create_ui;
fn create_display(event_loop: &glutin::event_loop::EventLoop<()>) -> glium::Display {

View File

@ -10,12 +10,12 @@ use std::sync::Arc;
use egui::panel::TopBottomSide;
use egui::{Layout, PointerButton};
#[cfg(feature = "xorg-glium")]
pub use glium_backend::run_app;
pub use glium_backend::*;
#[cfg(feature = "xorg-glow")]
pub use glow_backend::run_app;
pub use glow_backend::*;
use parking_lot::Mutex;
#[cfg(feature = "wayland")]
pub use wayland_backend::run_app;
pub use wayland_backend::*;
use crate::app::Page;
use crate::AmdGui;

View File

@ -81,7 +81,7 @@ pub fn run_app(amd_gui: Arc<Mutex<AmdGui>>, _receiver: UnboundedReceiver<bool>)
let event_loop = EventLoop::new();
let surface = WindowBuilder::new()
.with_title("egui_vulkano demo")
.with_title("AMD GUID")
.with_fullscreen(Some(Fullscreen::Borderless(None)))
.build_vk_surface(&event_loop, instance.clone())
.unwrap();
@ -176,32 +176,34 @@ pub fn run_app(amd_gui: Arc<Mutex<AmdGui>>, _receiver: UnboundedReceiver<bool>)
};
mod vs {
#![allow(clippy::needless_question_mark)]
vulkano_shaders::shader! {
ty: "vertex",
src: "
#version 450
#version 450
layout(location = 0) in vec2 position;
layout(location = 0) in vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
"
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
"
}
}
mod fs {
#![allow(clippy::needless_question_mark)]
vulkano_shaders::shader! {
ty: "fragment",
src: "
#version 450
#version 450
layout(location = 0) out vec4 f_color;
layout(location = 0) out vec4 f_color;
void main() {
f_color = vec4(1.0, 0.0, 0.0, 1.0);
}
"
void main() {
f_color = vec4(1.0, 0.0, 0.0, 1.0);
}
"
}
}
@ -220,7 +222,7 @@ pub fn run_app(amd_gui: Arc<Mutex<AmdGui>>, _receiver: UnboundedReceiver<bool>)
},
passes: [
{ color: [color], depth_stencil: {}, input: [] },
{ color: [color], depth_stencil: {}, input: [] } // Create a second renderpass to draw egui
{ color: [color], depth_stencil: {}, input: [] } // Create a second render-pass to draw egui
]
)
.unwrap();
@ -231,7 +233,7 @@ pub fn run_app(amd_gui: Arc<Mutex<AmdGui>>, _receiver: UnboundedReceiver<bool>)
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
.fragment_shader(fs.entry_point("main").unwrap(), ())
.render_pass(Subpass::from(render_pass.clone().into(), 0).unwrap())
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
.build(device.clone())
.unwrap();
@ -241,7 +243,8 @@ pub fn run_app(amd_gui: Arc<Mutex<AmdGui>>, _receiver: UnboundedReceiver<bool>)
depth_range: 0.0..1.0,
};
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
let mut frame_buffers =
window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
let mut recreate_swapchain = false;
@ -261,9 +264,6 @@ pub fn run_app(amd_gui: Arc<Mutex<AmdGui>>, _receiver: UnboundedReceiver<bool>)
//Set up some window to look at for the test
// let mut my_texture = egui_ctx.load_texture("my_texture",
// ColorImage::example());
event_loop.run(move |event, _, control_flow| {
match event {
Event::WindowEvent {
@ -304,7 +304,7 @@ pub fn run_app(amd_gui: Arc<Mutex<AmdGui>>, _receiver: UnboundedReceiver<bool>)
};
swapchain = new_swapchain;
framebuffers = window_size_dependent_setup(
frame_buffers = window_size_dependent_setup(
&new_images,
render_pass.clone(),
&mut viewport,
@ -352,7 +352,7 @@ pub fn run_app(amd_gui: Arc<Mutex<AmdGui>>, _receiver: UnboundedReceiver<bool>)
// Do your usual rendering
builder
.begin_render_pass(
framebuffers[image_num].clone(),
frame_buffers[image_num].clone(),
SubpassContents::Inline,
clear_values,
)

View File

@ -143,5 +143,5 @@ pub struct ExplicitGenerator {
#[inline(always)]
pub fn y_intersection(p1: &Pos2, p2: &Pos2, y: f32) -> Option<f32> {
((p1.y > y && p2.y < y) || (p1.y < y && p2.y > y))
.then(|| ((y * (p1.x - p2.x)) - (p1.x * p2.y - p1.y * p2.x)) / (p1.y - p2.y))
.then_some(((y * (p1.x - p2.x)) - (p1.x * p2.y - p1.y * p2.x)) / (p1.y - p2.y))
}

View File

@ -118,7 +118,7 @@ impl PlotItem for Points {
let default_stroke = Stroke::new(stroke_size, *color);
let mut stem_stroke = default_stroke;
let stroke = (!filled)
.then(|| default_stroke)
.then_some(default_stroke)
.unwrap_or_else(Stroke::none);
let fill = filled.then(|| *color).unwrap_or_default();

View File

@ -126,7 +126,7 @@ impl Values {
) -> Option<RangeInclusive<f64>> {
let start = range1.start().max(*range2.start());
let end = range1.end().min(*range2.end());
(start < end).then(|| start..=end)
(start < end).then_some(start..=end)
}
pub(crate) fn get_bounds(&self) -> Bounds {

View File

@ -149,10 +149,12 @@ impl ChangeFanSettings {
});
}
#[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) => {

View File

@ -15,6 +15,7 @@ pub struct CoolingPerformance {
}
impl CoolingPerformance {
#[allow(clippy::explicit_auto_deref)]
pub fn new(capacity: usize, fan_config: FanConfig) -> Self {
let amd_mon = amdgpu::hw_mon::open_hw_mon(Card(0))
.map(|hw| amdmond_lib::AmdMon::wrap(hw, &*fan_config.lock()))

View File

@ -260,6 +260,7 @@ impl DragPlotPrepared {
}
};
#[allow(clippy::explicit_auto_deref)]
shapes.push(Shape::text(
&*ui.fonts(),
pointer + vec2(3.0, -2.0),

View File

@ -43,7 +43,7 @@ impl LegendWidget {
LegendEntry::new(color, checked)
});
});
(!entries.is_empty()).then(|| Self {
(!entries.is_empty()).then_some(Self {
rect,
entries,
config,

View File

@ -1,69 +1,58 @@
use std::collections::HashMap;
use amdgpu::pidfile::ports::Output;
use egui::{Response, Sense, Ui, Vec2};
use epaint::Stroke;
pub struct OutputWidget<'output, 'textures> {
use crate::app::StatefulConfig;
pub struct OutputWidget<'output, 'stateful> {
output: &'output Output,
textures: &'textures HashMap<String, egui::TextureHandle>,
state: &'stateful mut StatefulConfig,
}
impl<'output, 'textures> OutputWidget<'output, 'textures> {
pub fn new(
output: &'output Output,
textures: &'textures HashMap<String, egui::TextureHandle>,
) -> Self {
Self { output, textures }
impl<'output, 'stateful> OutputWidget<'output, 'stateful> {
pub fn new(output: &'output Output, state: &'stateful mut StatefulConfig) -> Self {
Self { output, state }
}
}
impl<'output, 'textures> egui::Widget for OutputWidget<'output, 'textures> {
impl<'output, 'stateful> egui::Widget for OutputWidget<'output, 'stateful> {
fn ui(self, ui: &mut Ui) -> Response {
let (rect, res) = ui.allocate_exact_size(Vec2::new(80.0, 70.0), Sense::click());
// let _transform = ScreenTransform::new(rect, Bounds::new_symmetrical(1.0),
// false, false); let _frame = *transform.frame();
// eprintln!("min {:?} max {:?}", frame.min, frame.max);
let painter = ui.painter(); //.sub_region(*transform.frame());
let (rect, res) = ui.allocate_exact_size(Vec2::new(80.0, 80.0), Sense::click());
if let Some(handle) = self.output.ty.and_then(|ty| self.state.textures.get(&ty)) {
ui.image(handle.id(), handle.size_vec2());
} else {
let painter = ui.painter();
painter.rect_filled(rect, 0.0, epaint::color::Color32::DARK_RED);
painter.rect(rect, 2.0, epaint::color::Color32::DARK_RED, {
Stroke {
width: 1.0,
color: epaint::color::Color32::GREEN,
}
});
painter.rect_filled(rect, 0.0, epaint::color::Color32::DARK_RED);
painter.rect(rect, 2.0, epaint::color::Color32::DARK_RED, {
let mut s = Stroke::default();
s.color = epaint::color::Color32::GREEN;
s.width = 1.0;
s
});
let rect_middle_point = (rect.max - rect.min) / 2.0;
let rect_middle_point = (rect.max - rect.min) / 2.0;
painter.circle_filled(
rect.min + Vec2::new(rect_middle_point.x / 2.0, rect_middle_point.y),
3.0,
epaint::color::Color32::GREEN,
);
painter.circle_filled(
rect.min + rect_middle_point,
3.0,
epaint::color::Color32::GREEN,
);
painter.circle_filled(
rect.min + Vec2::new(rect_middle_point.x / 2.0, rect_middle_point.y),
3.0,
epaint::color::Color32::GREEN,
);
painter.circle_filled(
rect.min + rect_middle_point,
3.0,
epaint::color::Color32::GREEN,
);
painter.circle_filled(
rect.min
+ Vec2::new(
rect_middle_point.x + (rect_middle_point.x / 2.0),
rect_middle_point.y,
),
3.0,
epaint::color::Color32::GREEN,
);
painter.circle_filled(
rect.min
+ Vec2::new(
rect_middle_point.x + (rect_middle_point.x / 2.0),
rect_middle_point.y,
),
3.0,
epaint::color::Color32::GREEN,
);
}
res
}
}
fn icon(name: &str, textures: &HashMap<String, egui::TextureHandle>) {
if let Some(_texture) = textures.get(name) {
//
} else {
//
}
}

View File

@ -1,52 +1,22 @@
use std::collections::{BTreeMap, HashMap};
use std::collections::BTreeMap;
use amdgpu::pidfile::ports::{Output, Status};
use egui::Ui;
use epaint::ColorImage;
use image::ImageFormat;
use egui::{RichText, Ui, WidgetText};
use epaint::Color32;
use crate::app::StatefulConfig;
use crate::widgets::output_widget::OutputWidget;
#[derive(Default)]
pub struct OutputsSettings {
textures: HashMap<String, egui::TextureHandle>,
}
pub struct OutputsSettings {}
impl OutputsSettings {
pub fn draw(
&mut self,
ui: &mut Ui,
_state: &mut StatefulConfig,
state: &mut StatefulConfig,
outputs: &BTreeMap<String, Vec<Output>>,
) {
outputs.values().flatten().for_each(|output| {
// 160x160
let image = {
let bytes = include_bytes!("../../assets/icons/ports.jpg");
image::load_from_memory(bytes).unwrap()
};
for (_idx, _pixel, _p) in image.to_rgba8().enumerate_pixels() {
// let bytes = pixel.;
// eprintln!("{:?}", bytes);
}
if !self.textures.contains_key(&output.port_type) {
let img = image::load_from_memory_with_format(
include_bytes!("../../assets/icons/ports.jpg"),
ImageFormat::Jpeg,
)
.unwrap();
let image_buffer = img.to_rgba8();
let size = [image.width() as _, image.height() as _];
let pixels = image_buffer.as_flat_samples();
let _ = ui.ctx().load_texture(
output.port_type.clone(),
ColorImage::from_rgba_unmultiplied(size, pixels.as_slice()),
);
}
});
let _available = ui.available_rect_before_wrap();
ui.vertical(|ui| {
@ -57,7 +27,7 @@ impl OutputsSettings {
ui.horizontal_top(|ui| {
outputs.iter().for_each(|output| {
ui.vertical(|ui| {
ui.add(OutputWidget::new(output, &self.textures));
ui.add(OutputWidget::new(output, state));
ui.label(format!("port_number {}", output.port_number));
ui.label(format!("port_type {:?}", output.port_type));
@ -66,17 +36,27 @@ impl OutputsSettings {
"port_name {}",
output.port_name.as_deref().unwrap_or_default()
));
ui.label(match output.status {
Status::Connected => "Connected",
Status::Disconnected => "Disconnected",
});
let state = WidgetText::RichText(
RichText::new(match output.status {
Status::Connected => "Connected",
Status::Disconnected => "Disconnected",
})
.color(
match output.status {
Status::Connected => Color32::DARK_GREEN,
Status::Disconnected => Color32::GRAY,
},
),
);
ui.label(state);
});
});
});
});
});
});
// eprintln!("==============================================================");
});
}
}

View File

@ -19,9 +19,25 @@ fn parse_output(entry: DirEntry) -> Option<Output> {
.map(String::from)
.collect::<Vec<_>>()
.into_iter();
let modes = std::fs::read_to_string(entry.path().join("modes"))
.unwrap_or_default()
.lines()
.filter_map(|s| {
let mut it = s.split('x');
let width = it.next().and_then(|s| s.parse::<u16>().ok())?;
let height = it.next().and_then(|s| s.parse::<u16>().ok())?;
Some(OutputMode { width, height })
})
.collect::<Vec<_>>();
let card = it.next()?.strip_prefix("card")?.to_string();
let port_type = it.next()?;
let mut output = Output {
card: it.next()?.strip_prefix("card")?.to_string(),
port_type: it.next()?,
card,
ty: OutputType::parse_str(&port_type),
port_type,
modes,
..Default::default()
};
let mut it = it.rev();