mirror of
https://github.com/Astatin3/raylock.git
synced 2026-06-09 00:28:00 -06:00
Work on adding configurable panes
This commit is contained in:
@@ -8,3 +8,5 @@ eframe = "0.28"
|
|||||||
egui = "0.28"
|
egui = "0.28"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
serde = "1.0.214"
|
serde = "1.0.214"
|
||||||
|
serde_json = "1.0.132"
|
||||||
|
sysinfo = "0.32.0"
|
||||||
|
|||||||
@@ -40,3 +40,65 @@ pub const DOTS_COLOR: Color32 = Color32::from_rgb(255, 255, 255);
|
|||||||
|
|
||||||
pub const CORNER_CUT: f32 = LOGIN_CIRCLE_RADIUS * 1.41421356237;
|
pub const CORNER_CUT: f32 = LOGIN_CIRCLE_RADIUS * 1.41421356237;
|
||||||
pub const PANE_GAP: f32 = 6.;
|
pub const PANE_GAP: f32 = 6.;
|
||||||
|
|
||||||
|
// Example JSON configuration:
|
||||||
|
pub const EXAMPLE_CONFIG: &str = r#"
|
||||||
|
{
|
||||||
|
"root": {
|
||||||
|
"id": "root",
|
||||||
|
"split": {
|
||||||
|
"direction": "Horizontal",
|
||||||
|
"ratio": 0.9,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "left",
|
||||||
|
"pane_type": {
|
||||||
|
"type": "Solid",
|
||||||
|
"config": {
|
||||||
|
"color": [255, 255, 255]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "right",
|
||||||
|
"split": {
|
||||||
|
"direction": "Vertical",
|
||||||
|
"ratio": 0.6,
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"id": "right_top",
|
||||||
|
"pane_type": {
|
||||||
|
"type": "Text",
|
||||||
|
"config": {
|
||||||
|
"text": "Hello World",
|
||||||
|
"font_size": 24.0,
|
||||||
|
"color": [255, 255, 255],
|
||||||
|
"background_color": [50, 50, 150]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "right_bottom",
|
||||||
|
"pane_type": {
|
||||||
|
"type": "Gradient",
|
||||||
|
"config": {
|
||||||
|
"start_color": [200, 200, 200],
|
||||||
|
"end_color": [100, 200, 100],
|
||||||
|
"horizontal": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default_pane_type": {
|
||||||
|
"type": "Solid",
|
||||||
|
"config": {
|
||||||
|
"color": [200, 200, 200]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|||||||
+170
@@ -0,0 +1,170 @@
|
|||||||
|
use egui::{Color32, Pos2, Rect, Stroke, Vec2};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::time::Instant;
|
||||||
|
use sysinfo::System;
|
||||||
|
|
||||||
|
const HISTORY_SIZE: usize = 100;
|
||||||
|
const ANIMATION_DURATION: f32 = 0.2; // seconds
|
||||||
|
const UPDATES_PER_SECOND: f32 = 2.0;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct DataPoint {
|
||||||
|
value: f32,
|
||||||
|
timestamp: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct AnimatedValue {
|
||||||
|
current: f32,
|
||||||
|
target: f32,
|
||||||
|
last_update: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnimatedValue {
|
||||||
|
fn new(initial: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
current: initial,
|
||||||
|
target: initial,
|
||||||
|
last_update: Instant::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, new_target: f32) {
|
||||||
|
self.target = new_target;
|
||||||
|
self.last_update = Instant::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_current_value(&mut self) -> f32 {
|
||||||
|
let elapsed = self.last_update.elapsed().as_secs_f32();
|
||||||
|
let progress = (elapsed / ANIMATION_DURATION).min(1.0);
|
||||||
|
self.current = self.current + (self.target - self.current) * progress;
|
||||||
|
self.current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #[derive(Clone)]
|
||||||
|
//
|
||||||
|
// #[derive(Debug)]
|
||||||
|
pub struct CpuGraph {
|
||||||
|
sys: System,
|
||||||
|
history: Vec<VecDeque<DataPoint>>,
|
||||||
|
animated_values: Vec<AnimatedValue>,
|
||||||
|
last_update: Instant,
|
||||||
|
colors: Vec<Color32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CpuGraph {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let mut sys = System::new();
|
||||||
|
sys.refresh_cpu_all();
|
||||||
|
|
||||||
|
let cpu_count = sys.cpus().len();
|
||||||
|
let history = vec![VecDeque::with_capacity(HISTORY_SIZE); cpu_count];
|
||||||
|
let animated_values = vec![AnimatedValue::new(0.0); cpu_count];
|
||||||
|
|
||||||
|
// Generate distinct colors for each CPU core
|
||||||
|
let colors = (0..cpu_count)
|
||||||
|
.map(|i| {
|
||||||
|
let hue = (i as f32 / cpu_count as f32) * 360.0;
|
||||||
|
Color32::from_rgb(
|
||||||
|
((1.0 + (hue.sin())) * 127.5) as u8,
|
||||||
|
((1.0 + ((hue + 120.0).sin())) * 127.5) as u8,
|
||||||
|
((1.0 + ((hue + 240.0).sin())) * 127.5) as u8,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
sys,
|
||||||
|
history,
|
||||||
|
animated_values,
|
||||||
|
last_update: Instant::now(),
|
||||||
|
colors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self) {
|
||||||
|
let now = Instant::now();
|
||||||
|
if now.duration_since(self.last_update).as_secs_f32() < 1.0 / UPDATES_PER_SECOND {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.sys.refresh_cpu_all();
|
||||||
|
|
||||||
|
for (i, cpu) in self.sys.cpus().iter().enumerate() {
|
||||||
|
let usage = cpu.cpu_usage() / 100.0;
|
||||||
|
|
||||||
|
self.animated_values[i].update(usage);
|
||||||
|
|
||||||
|
self.history[i].push_back(DataPoint {
|
||||||
|
value: usage,
|
||||||
|
timestamp: now,
|
||||||
|
});
|
||||||
|
|
||||||
|
while self.history[i].len() > HISTORY_SIZE {
|
||||||
|
self.history[i].pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.last_update = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&mut self, painter: &egui::Painter, rect: Rect) {
|
||||||
|
let stroke_width = 2.0;
|
||||||
|
|
||||||
|
// Draw background
|
||||||
|
painter.rect_filled(rect, 0.0, Color32::from_gray(20));
|
||||||
|
|
||||||
|
// Draw grid lines
|
||||||
|
for i in 0..=4 {
|
||||||
|
let y = rect.min.y + rect.height() * (i as f32 / 4.0);
|
||||||
|
painter.line_segment(
|
||||||
|
[Pos2::new(rect.min.x, y), Pos2::new(rect.max.x, y)],
|
||||||
|
Stroke::new(1.0, Color32::from_gray(40)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw CPU usage lines
|
||||||
|
for (core_idx, (history, color)) in self.history.iter().zip(self.colors.iter()).enumerate()
|
||||||
|
{
|
||||||
|
if history.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let points: Vec<Pos2> = history
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, point)| {
|
||||||
|
let x = rect.min.x + rect.width() * (i as f32 / (HISTORY_SIZE - 1) as f32);
|
||||||
|
let y = rect.max.y - rect.height() * point.value;
|
||||||
|
Pos2::new(x, y)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Get the current animated value for the last point
|
||||||
|
let current_value = self.animated_values[core_idx].get_current_value();
|
||||||
|
let mut animated_points = points;
|
||||||
|
if let Some(last) = animated_points.last_mut() {
|
||||||
|
last.y = rect.max.y - rect.height() * current_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the line
|
||||||
|
painter.add(egui::Shape::line(
|
||||||
|
animated_points,
|
||||||
|
Stroke::new(stroke_width, *color),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw labels
|
||||||
|
for (i, color) in self.colors.iter().enumerate() {
|
||||||
|
let text = format!("CPU {}", i);
|
||||||
|
let pos = Pos2::new(rect.min.x + 5.0, rect.min.y + 15.0 + (i as f32 * 20.0));
|
||||||
|
painter.text(
|
||||||
|
pos,
|
||||||
|
egui::Align2::LEFT_TOP,
|
||||||
|
text,
|
||||||
|
egui::FontId::proportional(14.0),
|
||||||
|
*color,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+31
-8
@@ -1,14 +1,15 @@
|
|||||||
use eframe::{egui, App};
|
use eframe::{egui, App};
|
||||||
use egui::FontFamily;
|
use egui::FontFamily;
|
||||||
use egui::Key;
|
use egui::Key;
|
||||||
|
use graph::CpuGraph;
|
||||||
use input::is_locked;
|
use input::is_locked;
|
||||||
|
use panes::{PaneConfig, PaneRenderer, SplitDirection};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use structs::{PaneConfig, PaneRenderer, SplitDirection};
|
|
||||||
|
|
||||||
// use egui::epaint::text::{FontInsert, InsertFontFamily};
|
// use egui::epaint::text::{FontInsert, InsertFontFamily};
|
||||||
|
|
||||||
@@ -22,8 +23,9 @@ use egui::Stroke;
|
|||||||
use egui::ecolor::HexColor;
|
use egui::ecolor::HexColor;
|
||||||
|
|
||||||
mod configs;
|
mod configs;
|
||||||
|
mod graph;
|
||||||
mod input;
|
mod input;
|
||||||
mod splitter;
|
mod panes;
|
||||||
mod structs;
|
mod structs;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
@@ -59,11 +61,10 @@ mod ui;
|
|||||||
// ctx.set_fonts(fonts);
|
// ctx.set_fonts(fonts);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
use splitter::Splitter;
|
// #[derive(Default)]
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct ExampleApp {
|
struct ExampleApp {
|
||||||
auth_state: Arc<Mutex<structs::AuthState>>,
|
auth_state: Arc<Mutex<structs::AuthState>>,
|
||||||
|
cpu_graph: CpuGraph,
|
||||||
// terminals: HashMap<String, TermHandler>,
|
// terminals: HashMap<String, TermHandler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +103,10 @@ impl eframe::App for ExampleApp {
|
|||||||
|
|
||||||
let mut state = self.auth_state.lock().unwrap();
|
let mut state = self.auth_state.lock().unwrap();
|
||||||
//ctx.set_pixels_per_point(1.5);
|
//ctx.set_pixels_per_point(1.5);
|
||||||
let config = ui::winconfig();
|
// let config = ui::winconfig();
|
||||||
|
|
||||||
let pane_renderer = PaneRenderer::new(config);
|
let config: panes::LayoutConfig = serde_json::from_str(configs::EXAMPLE_CONFIG).unwrap();
|
||||||
|
let mut pane_renderer = PaneRenderer::new(config);
|
||||||
|
|
||||||
if ctx.input(|i| i.events.len() > 0) {
|
if ctx.input(|i| i.events.len() > 0) {
|
||||||
ctx.input(|i| {
|
ctx.input(|i| {
|
||||||
@@ -149,6 +151,8 @@ impl eframe::App for ExampleApp {
|
|||||||
// let sine_points2 = PlotPoints::from_explicit_callback(|x| x.sin(), .., 5000);
|
// let sine_points2 = PlotPoints::from_explicit_callback(|x| x.sin(), .., 5000);
|
||||||
// let plot_b_lines = [Line::new(sine_points2).name("Sine")];
|
// let plot_b_lines = [Line::new(sine_points2).name("Sine")];
|
||||||
|
|
||||||
|
// self.cpu_graph.update();
|
||||||
|
|
||||||
egui::CentralPanel::default()
|
egui::CentralPanel::default()
|
||||||
.frame(egui::Frame::none())
|
.frame(egui::Frame::none())
|
||||||
.show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
@@ -181,7 +185,17 @@ impl eframe::App for ExampleApp {
|
|||||||
// },
|
// },
|
||||||
// );
|
// );
|
||||||
|
|
||||||
ui::update_password_viewer(state, ctx, _frame, ui, pane_renderer);
|
ui::update_password_viewer(state, ctx, _frame, ui, &mut pane_renderer);
|
||||||
|
|
||||||
|
// self.cpu_graph.render(
|
||||||
|
// ui.painter(),
|
||||||
|
// egui::Rect {
|
||||||
|
// min: egui::Pos2 { x: 0., y: 0. },
|
||||||
|
// max: egui::Pos2 { x: 500., y: 500. },
|
||||||
|
// },
|
||||||
|
// );
|
||||||
|
|
||||||
|
ctx.request_repaint();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,6 +257,8 @@ fn main() -> eframe::Result<()> {
|
|||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let test = [1, 2, 3];
|
||||||
|
|
||||||
input::create_lock();
|
input::create_lock();
|
||||||
|
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
@@ -251,12 +267,19 @@ fn main() -> eframe::Result<()> {
|
|||||||
Box::new(|_| {
|
Box::new(|_| {
|
||||||
Ok(Box::<ExampleApp>::new(ExampleApp {
|
Ok(Box::<ExampleApp>::new(ExampleApp {
|
||||||
auth_state: state,
|
auth_state: state,
|
||||||
|
cpu_graph: CpuGraph::new(),
|
||||||
// terminals: map,
|
// terminals: map,
|
||||||
}))
|
}))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_test(test: &mut [i32]) {
|
||||||
|
for i in 0..test.len() {
|
||||||
|
test[i] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn try_sudo(password: &str) -> Result<bool, std::io::Error> {
|
fn try_sudo(password: &str) -> Result<bool, std::io::Error> {
|
||||||
let mut child = Command::new("sudo")
|
let mut child = Command::new("sudo")
|
||||||
.args(["-kS", "true"]) // Use -S to read password from stdin
|
.args(["-kS", "true"]) // Use -S to read password from stdin
|
||||||
|
|||||||
+398
@@ -0,0 +1,398 @@
|
|||||||
|
use egui::{Color32, Painter, Pos2, Rect};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{graph::CpuGraph, ui};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
|
pub enum CornerTypes {
|
||||||
|
SQUARE,
|
||||||
|
Ang45,
|
||||||
|
Ang30,
|
||||||
|
Ang60,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serializable configuration types
|
||||||
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
|
pub enum SplitDirection {
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(tag = "type", content = "config")]
|
||||||
|
pub enum PaneTypeConfig {
|
||||||
|
Solid(SolidPaneConfig),
|
||||||
|
Text(TextPaneConfig),
|
||||||
|
Gradient(GradientPaneConfig),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runtime-only pane type that includes non-serializable data
|
||||||
|
// #[derive(Clone)]
|
||||||
|
pub enum PaneType {
|
||||||
|
Solid(SolidPane),
|
||||||
|
Text(TextPane),
|
||||||
|
Gradient(GradientPane),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serializable configs
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct SolidPaneConfig {
|
||||||
|
pub color: [u8; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct TextPaneConfig {
|
||||||
|
pub text: String,
|
||||||
|
pub font_size: f32,
|
||||||
|
pub color: [u8; 3],
|
||||||
|
pub background_color: Option<[u8; 3]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct GradientPaneConfig {
|
||||||
|
pub start_color: [u8; 3],
|
||||||
|
pub end_color: [u8; 3],
|
||||||
|
pub horizontal: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runtime types with additional non-serializable data
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SolidPane {
|
||||||
|
config: SolidPaneConfig,
|
||||||
|
// Runtime-only fields
|
||||||
|
cached_color: Color32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct TextPane {
|
||||||
|
config: TextPaneConfig,
|
||||||
|
// Runtime-only fields
|
||||||
|
cached_color: Color32,
|
||||||
|
cached_bg_color: Option<Color32>,
|
||||||
|
cached_font: egui::FontId,
|
||||||
|
}
|
||||||
|
|
||||||
|
// #[derive(Clone)]
|
||||||
|
pub struct GradientPane {
|
||||||
|
config: GradientPaneConfig,
|
||||||
|
// Runtime-only fields
|
||||||
|
cached_start_color: Color32,
|
||||||
|
cached_end_color: Color32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct PaneConfig {
|
||||||
|
pub id: String,
|
||||||
|
#[serde(default)]
|
||||||
|
pub split: Option<SplitConfig>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub pane_type: Option<PaneTypeConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct SplitConfig {
|
||||||
|
pub direction: SplitDirection,
|
||||||
|
pub ratio: f32,
|
||||||
|
pub children: Vec<PaneConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct LayoutConfig {
|
||||||
|
pub root: PaneConfig,
|
||||||
|
#[serde(default)]
|
||||||
|
pub default_pane_type: Option<PaneTypeConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runtime representation of the layout
|
||||||
|
pub struct RuntimePane {
|
||||||
|
pub id: String,
|
||||||
|
pub split: Option<RuntimeSplit>,
|
||||||
|
pub pane_type: Option<PaneType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RuntimeSplit {
|
||||||
|
pub direction: SplitDirection,
|
||||||
|
pub ratio: f32,
|
||||||
|
pub children: Vec<RuntimePane>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion implementations
|
||||||
|
impl From<PaneTypeConfig> for PaneType {
|
||||||
|
fn from(config: PaneTypeConfig) -> Self {
|
||||||
|
match config {
|
||||||
|
PaneTypeConfig::Solid(config) => PaneType::Solid(SolidPane {
|
||||||
|
cached_color: Color32::from_rgb(config.color[0], config.color[1], config.color[2]),
|
||||||
|
config,
|
||||||
|
}),
|
||||||
|
PaneTypeConfig::Text(config) => PaneType::Text(TextPane {
|
||||||
|
cached_color: Color32::from_rgb(config.color[0], config.color[1], config.color[2]),
|
||||||
|
cached_bg_color: config
|
||||||
|
.background_color
|
||||||
|
.map(|c| Color32::from_rgb(c[0], c[1], c[2])),
|
||||||
|
cached_font: egui::FontId::proportional(config.font_size),
|
||||||
|
config,
|
||||||
|
}),
|
||||||
|
PaneTypeConfig::Gradient(config) => PaneType::Gradient(GradientPane {
|
||||||
|
cached_start_color: Color32::from_rgb(
|
||||||
|
config.start_color[0],
|
||||||
|
config.start_color[1],
|
||||||
|
config.start_color[2],
|
||||||
|
),
|
||||||
|
cached_end_color: Color32::from_rgb(
|
||||||
|
config.end_color[0],
|
||||||
|
config.end_color[1],
|
||||||
|
config.end_color[2],
|
||||||
|
),
|
||||||
|
|
||||||
|
config,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PaneType {
|
||||||
|
fn render(&self, painter: &Painter, rect: Rect) {
|
||||||
|
ui::background_render(
|
||||||
|
painter,
|
||||||
|
rect,
|
||||||
|
[
|
||||||
|
CornerTypes::Ang30,
|
||||||
|
CornerTypes::Ang60,
|
||||||
|
CornerTypes::Ang30,
|
||||||
|
CornerTypes::Ang60,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
match self {
|
||||||
|
PaneType::Solid(pane) => {
|
||||||
|
// painter.rect_filled(rect, 0.0, pane.cached_color);
|
||||||
|
// painter.rect_stroke(rect, 0.0, (1.0, Color32::BLACK));
|
||||||
|
}
|
||||||
|
PaneType::Text(pane) => {
|
||||||
|
// if let Some(bg_color) = pane.cached_bg_color {
|
||||||
|
// painter.rect_filled(rect, 0.0, bg_color);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// painter.text(
|
||||||
|
// rect.center(),
|
||||||
|
// egui::Align2::CENTER_CENTER,
|
||||||
|
// &pane.config.text,
|
||||||
|
// pane.cached_font.clone(),
|
||||||
|
// pane.cached_color,
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
PaneType::Gradient(pane) => {
|
||||||
|
let mut pane2 = pane;
|
||||||
|
// pane.cpu_graph.update();
|
||||||
|
// pane.cpu_graph.render(painter, rect);
|
||||||
|
// if pane.config.horizontal {
|
||||||
|
// painter.rect_filled(rect, 0.0, pane.cached_start_color); // Simplified
|
||||||
|
// } else {
|
||||||
|
// painter.rect_filled(rect, 0.0, pane.cached_end_color); // Simplified
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PaneRenderer {
|
||||||
|
runtime_config: RuntimePane,
|
||||||
|
default_pane_type: Option<PaneType>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PaneRenderer {
|
||||||
|
pub fn new(config: LayoutConfig) -> Self {
|
||||||
|
Self {
|
||||||
|
runtime_config: Self::convert_config(&config.root),
|
||||||
|
default_pane_type: config.default_pane_type.map(Into::into),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_config(config: &PaneConfig) -> RuntimePane {
|
||||||
|
RuntimePane {
|
||||||
|
id: config.id.clone(),
|
||||||
|
split: config.split.as_ref().map(|split| RuntimeSplit {
|
||||||
|
direction: split.direction,
|
||||||
|
ratio: split.ratio,
|
||||||
|
children: split.children.iter().map(Self::convert_config).collect(),
|
||||||
|
}),
|
||||||
|
pane_type: config.pane_type.clone().map(Into::into),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, painter: &Painter, rect: &Rect) {
|
||||||
|
self.render_pane(painter, &rect, &self.runtime_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_pane(&self, painter: &Painter, rect: &Rect, pane: &RuntimePane) {
|
||||||
|
if let Some(split) = &pane.split {
|
||||||
|
if !split.children.is_empty() {
|
||||||
|
let rects =
|
||||||
|
self.split_rect(rect, split.direction, split.ratio, split.children.len());
|
||||||
|
|
||||||
|
for (child, child_rect) in split.children.iter().zip(&rects) {
|
||||||
|
self.render_pane(painter, child_rect, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw split lines
|
||||||
|
let split_line_color = Color32::from_gray(128);
|
||||||
|
match split.direction {
|
||||||
|
SplitDirection::Horizontal => {
|
||||||
|
for rect in rects.windows(2) {
|
||||||
|
let x = rect[0].max.x;
|
||||||
|
painter.line_segment(
|
||||||
|
[Pos2::new(x, rect[0].min.y), Pos2::new(x, rect[0].max.y)],
|
||||||
|
(1.0, split_line_color),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SplitDirection::Vertical => {
|
||||||
|
for rect in rects.windows(2) {
|
||||||
|
let y = rect[0].max.y;
|
||||||
|
painter.line_segment(
|
||||||
|
[Pos2::new(rect[0].min.x, y), Pos2::new(rect[0].max.x, y)],
|
||||||
|
(1.0, split_line_color),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Render leaf pane
|
||||||
|
let pane_type = &mut pane.pane_type.as_ref();
|
||||||
|
|
||||||
|
if let Some(pane_type) = pane_type {
|
||||||
|
pane_type.render(painter, *rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn split_rect(
|
||||||
|
&self,
|
||||||
|
rect: &Rect,
|
||||||
|
direction: SplitDirection,
|
||||||
|
ratio: f32,
|
||||||
|
count: usize,
|
||||||
|
) -> Vec<Rect> {
|
||||||
|
let mut rects = Vec::with_capacity(count);
|
||||||
|
let size = match direction {
|
||||||
|
SplitDirection::Horizontal => rect.width(),
|
||||||
|
SplitDirection::Vertical => rect.height(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let first_size = size * ratio;
|
||||||
|
let remaining_size = size - first_size;
|
||||||
|
let size_per_remaining = if count > 1 {
|
||||||
|
remaining_size / (count as f32 - 1.0)
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
|
||||||
|
for i in 0..count {
|
||||||
|
let (start, end) = match direction {
|
||||||
|
SplitDirection::Horizontal => {
|
||||||
|
let start = if i == 0 {
|
||||||
|
rect.min.x
|
||||||
|
} else {
|
||||||
|
rect.min.x + first_size + size_per_remaining * (i as f32 - 1.0)
|
||||||
|
};
|
||||||
|
let end = if i == 0 {
|
||||||
|
rect.min.x + first_size
|
||||||
|
} else {
|
||||||
|
start + size_per_remaining
|
||||||
|
};
|
||||||
|
(Pos2::new(start, rect.min.y), Pos2::new(end, rect.max.y))
|
||||||
|
}
|
||||||
|
SplitDirection::Vertical => {
|
||||||
|
let start = if i == 0 {
|
||||||
|
rect.min.y
|
||||||
|
} else {
|
||||||
|
rect.min.y + first_size + size_per_remaining * (i as f32 - 1.0)
|
||||||
|
};
|
||||||
|
let end = if i == 0 {
|
||||||
|
rect.min.y + first_size
|
||||||
|
} else {
|
||||||
|
start + size_per_remaining
|
||||||
|
};
|
||||||
|
(Pos2::new(rect.min.x, start), Pos2::new(rect.max.x, end))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
rects.push(Rect::from_min_max(start, end));
|
||||||
|
}
|
||||||
|
rects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Example JSON configuration:
|
||||||
|
// const EXAMPLE_CONFIG: &str = r#"
|
||||||
|
// {
|
||||||
|
// "root": {
|
||||||
|
// "id": "root",
|
||||||
|
// "split": {
|
||||||
|
// "direction": "Horizontal",
|
||||||
|
// "ratio": 0.3,
|
||||||
|
// "children": [
|
||||||
|
// {
|
||||||
|
// "id": "left",
|
||||||
|
// "pane_type": {
|
||||||
|
// "type": "Solid",
|
||||||
|
// "config": {
|
||||||
|
// "color": [100, 150, 200]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": "right",
|
||||||
|
// "split": {
|
||||||
|
// "direction": "Vertical",
|
||||||
|
// "ratio": 0.6,
|
||||||
|
// "children": [
|
||||||
|
// {
|
||||||
|
// "id": "right_top",
|
||||||
|
// "pane_type": {
|
||||||
|
// "type": "Text",
|
||||||
|
// "config": {
|
||||||
|
// "text": "Hello World",
|
||||||
|
// "font_size": 24.0,
|
||||||
|
// "color": [255, 255, 255],
|
||||||
|
// "background_color": [50, 50, 150]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// "id": "right_bottom",
|
||||||
|
// "pane_type": {
|
||||||
|
// "type": "Gradient",
|
||||||
|
// "config": {
|
||||||
|
// "start_color": [200, 100, 100],
|
||||||
|
// "end_color": [100, 200, 100],
|
||||||
|
// "horizontal": true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// "default_pane_type": {
|
||||||
|
// "type": "Solid",
|
||||||
|
// "config": {
|
||||||
|
// "color": [200, 200, 200]
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// "#;
|
||||||
|
|
||||||
|
// // Example usage
|
||||||
|
// pub fn example_usage(ctx: &egui::Context) {
|
||||||
|
// // Parse configuration
|
||||||
|
// let config: LayoutConfig = serde_json::from_str(EXAMPLE_CONFIG).unwrap();
|
||||||
|
// let pane_renderer = PaneRenderer::new(config);
|
||||||
|
|
||||||
|
// // egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
|
// // let painter = ui.painter();
|
||||||
|
|
||||||
|
// // });
|
||||||
|
// }
|
||||||
+161
-219
@@ -13,233 +13,175 @@ pub struct AuthState {
|
|||||||
pub failed_attempts: u16,
|
pub failed_attempts: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub enum windowTypes {
|
// #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
// Temp1,
|
// pub enum SplitDirection {
|
||||||
// Temp2,
|
// Horizontal,
|
||||||
|
// Vertical,
|
||||||
// SplitVertical,
|
|
||||||
// SplitHorisontal,
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// pub struct Pane {
|
// // #[derive(Sized)]
|
||||||
// pub wintype: windowTypes,
|
// pub struct PaneConfig {
|
||||||
|
// pub id: String,
|
||||||
|
// pub split: Option<(SplitDirection, f32)>,
|
||||||
|
// pub children: Option<Vec<PaneConfig>>,
|
||||||
|
// pub color: Option<Color32>, // Store color in config for consistency
|
||||||
|
// pub callback: Option<Box<dyn Fn(&Painter, Rect, [CornerTypes; 4])>>,
|
||||||
|
// pub corners: [CornerTypes; 4],
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// pub struct PaneSplit {
|
// // #[derive(Debug)]
|
||||||
// pub wintype: windowTypes,
|
// pub struct PaneRenderer {
|
||||||
// pub sub_a: Pane,
|
// config: PaneConfig,
|
||||||
// pub sub_b: Pane,
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// impl Pane {
|
// impl PaneConfig {
|
||||||
// pub const fn new(wintype: windowTypes) -> Self {
|
// pub fn new(id: impl Into<String>) -> Self {
|
||||||
// Self { wintype: wintype }
|
// Self {
|
||||||
// }
|
// id: id.into(),
|
||||||
|
// split: None,
|
||||||
// pub const fn new_hsplit(wintype: windowTypes, left: Pane, right: Pane) -> PaneSplit {
|
// children: None,
|
||||||
// PaneSplit {
|
// color: None,
|
||||||
// wintype: wintype,
|
// callback: None,
|
||||||
// sub_a: left,
|
// corners: [
|
||||||
// sub_b: right,
|
// CornerTypes::Ang60,
|
||||||
|
// CornerTypes::Ang30,
|
||||||
|
// CornerTypes::SQUARE,
|
||||||
|
// CornerTypes::Ang45,
|
||||||
|
// ],
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// pub const fn new_rsplit(wintype: windowTypes, wintop: Pane, bottom: Pane) -> PaneSplit {
|
|
||||||
// PaneSplit {
|
// pub fn with_split(mut self, direction: SplitDirection, ratio: f32) -> Self {
|
||||||
// wintype: wintype,
|
// self.split = Some((direction, ratio.clamp(0.0, 1.0)));
|
||||||
// sub_a: top,
|
// self
|
||||||
// sub_b: bottom,
|
// }
|
||||||
|
|
||||||
|
// pub fn with_children(mut self, children: Vec<PaneConfig>) -> Self {
|
||||||
|
// self.children = Some(children);
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn with_callback(
|
||||||
|
// mut self,
|
||||||
|
// callback: impl Fn(&Painter, Rect, [CornerTypes; 4]) + 'static,
|
||||||
|
// ) -> Self {
|
||||||
|
// self.callback = Some(Box::new(callback));
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn with_corners(mut self, corners: [CornerTypes; 4]) -> Self {
|
||||||
|
// self.corners = corners;
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn with_corner_tl(mut self, corner: CornerTypes) -> Self {
|
||||||
|
// self.corners[0] = corner;
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
// pub fn with_corner_tr(mut self, corner: CornerTypes) -> Self {
|
||||||
|
// self.corners[1] = corner;
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
// pub fn with_corner_br(mut self, corner: CornerTypes) -> Self {
|
||||||
|
// self.corners[2] = corner;
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
// pub fn with_corner_bl(mut self, corner: CornerTypes) -> Self {
|
||||||
|
// self.corners[3] = corner;
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn with_random_color(mut self) -> Self {
|
||||||
|
// let mut rng = rand::thread_rng();
|
||||||
|
// self.color = Some(Color32::from_rgb(
|
||||||
|
// rng.gen_range(0..255),
|
||||||
|
// rng.gen_range(0..255),
|
||||||
|
// rng.gen_range(0..255),
|
||||||
|
// ));
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl PaneRenderer {
|
||||||
|
// pub fn new(config: PaneConfig) -> Self {
|
||||||
|
// Self { config }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn render(&self, painter: &Painter, rect: Rect) {
|
||||||
|
// self.render_pane(painter, rect, &self.config);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn render_pane(&self, painter: &Painter, rect: Rect, pane: &PaneConfig) {
|
||||||
|
// if let Some((direction, ratio)) = &pane.split {
|
||||||
|
// if let Some(children) = &pane.children {
|
||||||
|
// if children.len() >= 2 {
|
||||||
|
// let (first_rect, second_rect) = self.split_rect(rect, *direction, *ratio);
|
||||||
|
|
||||||
|
// // Render first child
|
||||||
|
// self.render_pane(painter, first_rect, &children[0]);
|
||||||
|
|
||||||
|
// // Render second child
|
||||||
|
// self.render_pane(painter, second_rect, &children[1]);
|
||||||
|
|
||||||
|
// // Render any additional children (will be stacked after the split)
|
||||||
|
// let remaining_rect = match direction {
|
||||||
|
// SplitDirection::Horizontal => Rect::from_min_size(
|
||||||
|
// Pos2::new(second_rect.max.x, rect.min.y),
|
||||||
|
// Vec2::new(rect.max.x - second_rect.max.x, rect.height()),
|
||||||
|
// ),
|
||||||
|
// SplitDirection::Vertical => Rect::from_min_size(
|
||||||
|
// Pos2::new(rect.min.x, second_rect.max.y),
|
||||||
|
// Vec2::new(rect.width(), rect.max.y - second_rect.max.y),
|
||||||
|
// ),
|
||||||
|
// };
|
||||||
|
|
||||||
|
// for child in children.iter().skip(2) {
|
||||||
|
// self.render_pane(painter, remaining_rect, child);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Draw split line
|
||||||
|
// let split_line_color = Color32::from_gray(128);
|
||||||
|
// match direction {
|
||||||
|
// SplitDirection::Horizontal => {
|
||||||
|
// let x = first_rect.max.x;
|
||||||
|
// // painter.line_segment(
|
||||||
|
// // [Pos2::new(x, rect.min.y), Pos2::new(x, rect.max.y)],
|
||||||
|
// // (1.0, split_line_color),
|
||||||
|
// // );
|
||||||
|
// }
|
||||||
|
// SplitDirection::Vertical => {
|
||||||
|
// let y = first_rect.max.y;
|
||||||
|
// // painter.line_segment(
|
||||||
|
// // [Pos2::new(rect.min.x, y), Pos2::new(rect.max.x, y)],
|
||||||
|
// // (1.0, split_line_color),
|
||||||
|
// // );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// if !pane.callback.is_none() {
|
||||||
|
// // (&self.config).corners[0] = CornerTypes::Ang30;
|
||||||
|
// pane.callback.as_ref().unwrap()(painter, rect, self.config.corners);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn split_rect(&self, rect: Rect, direction: SplitDirection, ratio: f32) -> (Rect, Rect) {
|
||||||
|
// match direction {
|
||||||
|
// SplitDirection::Horizontal => {
|
||||||
|
// let split_x = rect.min.x + rect.width() * ratio;
|
||||||
|
// let first = Rect::from_min_max(rect.min, Pos2::new(split_x, rect.max.y));
|
||||||
|
// let second = Rect::from_min_max(Pos2::new(split_x, rect.min.y), rect.max);
|
||||||
|
// (first, second)
|
||||||
|
// }
|
||||||
|
// SplitDirection::Vertical => {
|
||||||
|
// let split_y = rect.min.y + rect.height() * ratio;
|
||||||
|
// let first = Rect::from_min_max(rect.min, Pos2::new(rect.max.x, split_y));
|
||||||
|
// let second = Rect::from_min_max(Pos2::new(rect.min.x, split_y), rect.max);
|
||||||
|
// (first, second)
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// pub struct cur_context {
|
|
||||||
// pub state: AuthState,
|
|
||||||
|
|
||||||
// pub ctx: egui::Context,
|
|
||||||
// pub frame: eframe::Frame,
|
|
||||||
// pub ui: egui::Ui,
|
|
||||||
|
|
||||||
// pub center: egui::Pos2,
|
|
||||||
// pub painter: egui::Painter,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[derive(Debug)]
|
|
||||||
// type PaintCallback = dyn Fn() -> String;
|
|
||||||
|
|
||||||
// impl fmt::Debug for PaintCallback {
|
|
||||||
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
// write!("Test")
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
|
||||||
pub enum SplitDirection {
|
|
||||||
Horizontal,
|
|
||||||
Vertical,
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[derive(Sized)]
|
|
||||||
pub struct PaneConfig {
|
|
||||||
pub id: String,
|
|
||||||
pub split: Option<(SplitDirection, f32)>,
|
|
||||||
pub children: Option<Vec<PaneConfig>>,
|
|
||||||
pub color: Option<Color32>, // Store color in config for consistency
|
|
||||||
pub callback: Option<Box<dyn Fn(&Painter, Rect)>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[derive(Debug)]
|
|
||||||
pub struct PaneRenderer {
|
|
||||||
config: PaneConfig,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PaneConfig {
|
|
||||||
pub fn new(id: impl Into<String>) -> Self {
|
|
||||||
Self {
|
|
||||||
id: id.into(),
|
|
||||||
split: None,
|
|
||||||
children: None,
|
|
||||||
color: None,
|
|
||||||
callback: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_split(mut self, direction: SplitDirection, ratio: f32) -> Self {
|
|
||||||
self.split = Some((direction, ratio.clamp(0.0, 1.0)));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_children(mut self, children: Vec<PaneConfig>) -> Self {
|
|
||||||
self.children = Some(children);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_callback(mut self, callback: impl Fn(&Painter, Rect) + 'static) -> Self {
|
|
||||||
self.callback = Some(Box::new(callback));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_random_color(mut self) -> Self {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
self.color = Some(Color32::from_rgb(
|
|
||||||
rng.gen_range(0..255),
|
|
||||||
rng.gen_range(0..255),
|
|
||||||
rng.gen_range(0..255),
|
|
||||||
));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PaneRenderer {
|
|
||||||
pub fn new(config: PaneConfig) -> Self {
|
|
||||||
Self { config }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn render(&self, painter: &Painter, rect: Rect) {
|
|
||||||
self.render_pane(painter, rect, &self.config);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_pane(&self, painter: &Painter, rect: Rect, pane: &PaneConfig) {
|
|
||||||
if let Some((direction, ratio)) = &pane.split {
|
|
||||||
if let Some(children) = &pane.children {
|
|
||||||
if children.len() >= 2 {
|
|
||||||
let (first_rect, second_rect) = self.split_rect(rect, *direction, *ratio);
|
|
||||||
|
|
||||||
// Render first child
|
|
||||||
self.render_pane(painter, first_rect, &children[0]);
|
|
||||||
|
|
||||||
// Render second child
|
|
||||||
self.render_pane(painter, second_rect, &children[1]);
|
|
||||||
|
|
||||||
// Render any additional children (will be stacked after the split)
|
|
||||||
let remaining_rect = match direction {
|
|
||||||
SplitDirection::Horizontal => Rect::from_min_size(
|
|
||||||
Pos2::new(second_rect.max.x, rect.min.y),
|
|
||||||
Vec2::new(rect.max.x - second_rect.max.x, rect.height()),
|
|
||||||
),
|
|
||||||
SplitDirection::Vertical => Rect::from_min_size(
|
|
||||||
Pos2::new(rect.min.x, second_rect.max.y),
|
|
||||||
Vec2::new(rect.width(), rect.max.y - second_rect.max.y),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
for child in children.iter().skip(2) {
|
|
||||||
self.render_pane(painter, remaining_rect, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw split line
|
|
||||||
let split_line_color = Color32::from_gray(128);
|
|
||||||
match direction {
|
|
||||||
SplitDirection::Horizontal => {
|
|
||||||
let x = first_rect.max.x;
|
|
||||||
// painter.line_segment(
|
|
||||||
// [Pos2::new(x, rect.min.y), Pos2::new(x, rect.max.y)],
|
|
||||||
// (1.0, split_line_color),
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
SplitDirection::Vertical => {
|
|
||||||
let y = first_rect.max.y;
|
|
||||||
// painter.line_segment(
|
|
||||||
// [Pos2::new(rect.min.x, y), Pos2::new(rect.max.x, y)],
|
|
||||||
// (1.0, split_line_color),
|
|
||||||
// );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !pane.callback.is_none() {
|
|
||||||
pane.callback.as_ref().unwrap()(painter, rect);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn split_rect(&self, rect: Rect, direction: SplitDirection, ratio: f32) -> (Rect, Rect) {
|
|
||||||
match direction {
|
|
||||||
SplitDirection::Horizontal => {
|
|
||||||
let split_x = rect.min.x + rect.width() * ratio;
|
|
||||||
let first = Rect::from_min_max(rect.min, Pos2::new(split_x, rect.max.y));
|
|
||||||
let second = Rect::from_min_max(Pos2::new(split_x, rect.min.y), rect.max);
|
|
||||||
(first, second)
|
|
||||||
}
|
|
||||||
SplitDirection::Vertical => {
|
|
||||||
let split_y = rect.min.y + rect.height() * ratio;
|
|
||||||
let first = Rect::from_min_max(rect.min, Pos2::new(rect.max.x, split_y));
|
|
||||||
let second = Rect::from_min_max(Pos2::new(rect.min.x, split_y), rect.max);
|
|
||||||
(first, second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Example usage in an app
|
|
||||||
pub fn example_usage(ctx: &egui::Context) {
|
|
||||||
// Create a complex pane configuration
|
|
||||||
let config = PaneConfig::new("root")
|
|
||||||
.with_split(SplitDirection::Horizontal, 0.3)
|
|
||||||
.with_children(vec![
|
|
||||||
PaneConfig::new("left").with_random_color(),
|
|
||||||
PaneConfig::new("right")
|
|
||||||
.with_split(SplitDirection::Vertical, 0.6)
|
|
||||||
.with_children(vec![
|
|
||||||
PaneConfig::new("right_top").with_random_color(),
|
|
||||||
PaneConfig::new("right_bottom")
|
|
||||||
.with_split(SplitDirection::Horizontal, 0.5)
|
|
||||||
.with_children(vec![
|
|
||||||
PaneConfig::new("bottom_left").with_random_color(),
|
|
||||||
PaneConfig::new("bottom_right").with_random_color(),
|
|
||||||
]),
|
|
||||||
]),
|
|
||||||
]);
|
|
||||||
|
|
||||||
let pane_renderer = PaneRenderer::new(config);
|
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
|
||||||
// Get the painter and available rect from the UI
|
|
||||||
let painter = ui.painter();
|
|
||||||
let rect = ui.available_rect_before_wrap();
|
|
||||||
|
|
||||||
// Render the panes
|
|
||||||
pane_renderer.render(&painter, rect);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
use crate::configs::*;
|
use crate::configs::*;
|
||||||
|
use crate::graph::CpuGraph;
|
||||||
|
use crate::panes;
|
||||||
use crate::structs;
|
use crate::structs;
|
||||||
use crate::structs::PaneRenderer;
|
use panes::PaneRenderer;
|
||||||
// use crate::structs::cur_context;
|
// use crate::structs::cur_context;
|
||||||
// use crate::structs::windowTypes;
|
// use crate::structs::windowTypes;
|
||||||
|
|
||||||
use eframe::egui;
|
use eframe::egui;
|
||||||
use egui::Color32;
|
use egui::Color32;
|
||||||
use egui::Pos2;
|
|
||||||
use egui::Shape;
|
use egui::Shape;
|
||||||
|
use egui::{Pos2, Vec2};
|
||||||
|
use panes::{PaneConfig, SplitDirection};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use structs::{PaneConfig, SplitDirection};
|
|
||||||
|
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::MutexGuard;
|
use std::sync::MutexGuard;
|
||||||
@@ -22,108 +24,115 @@ fn rot_circle(i: i16, center: Pos2, rad: f32, offset_ang: f32, ang_per_num: f32)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn background_render(painter: &egui::Painter, rect: egui::Rect) {
|
fn add_Pos2(add: Vec2, points: &mut Vec<Pos2>) -> &mut Vec<Pos2> {
|
||||||
|
for i in 0..points.len() {
|
||||||
|
points[i] = points[i] + add;
|
||||||
|
}
|
||||||
|
points
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mult_Pos2(mult: f32, points: &mut Vec<Pos2>) -> &mut Vec<Pos2> {
|
||||||
|
let vec = Vec2 { x: mult, y: mult };
|
||||||
|
for i in 0..points.len() {
|
||||||
|
points[i] = points[i] * mult;
|
||||||
|
}
|
||||||
|
points
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotate_90(points: &mut Vec<Pos2>) -> &mut Vec<Pos2> {
|
||||||
|
for i in 0..points.len() {
|
||||||
|
points[i] = Pos2 {
|
||||||
|
x: -points[i].y,
|
||||||
|
y: points[i].x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
points
|
||||||
|
}
|
||||||
|
fn rotate_180(points: &mut Vec<Pos2>) -> &mut Vec<Pos2> {
|
||||||
|
for i in 0..points.len() {
|
||||||
|
points[i] = Pos2 {
|
||||||
|
x: -points[i].x,
|
||||||
|
y: -points[i].y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
points
|
||||||
|
}
|
||||||
|
fn rotate_270(points: &mut Vec<Pos2>) -> &mut Vec<Pos2> {
|
||||||
|
for i in 0..points.len() {
|
||||||
|
points[i] = Pos2 {
|
||||||
|
x: points[i].y,
|
||||||
|
y: -points[i].x,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
points
|
||||||
|
}
|
||||||
|
|
||||||
|
const CORNER_SQUARE: [Pos2; 1] = [Pos2 { x: 0., y: 0. }];
|
||||||
|
const CORNER_45: [Pos2; 2] = [Pos2 { x: 0., y: 1. }, Pos2 { x: 1., y: 0. }];
|
||||||
|
const CORNER_30: [Pos2; 2] = [Pos2 { x: 0., y: 0.5 }, Pos2 { x: 1., y: 0. }];
|
||||||
|
const CORNER_60: [Pos2; 2] = [Pos2 { x: 0., y: 1. }, Pos2 { x: 0.5, y: 0. }];
|
||||||
|
|
||||||
|
fn get_corner_points(ctype: panes::CornerTypes) -> Vec<Pos2> {
|
||||||
|
// CORNER_30.to_vec()
|
||||||
|
match ctype {
|
||||||
|
panes::CornerTypes::SQUARE => CORNER_SQUARE.to_vec(),
|
||||||
|
panes::CornerTypes::Ang30 => CORNER_30.to_vec(),
|
||||||
|
panes::CornerTypes::Ang45 => CORNER_45.to_vec(),
|
||||||
|
panes::CornerTypes::Ang60 => CORNER_60.to_vec(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn background_render(
|
||||||
|
painter: &egui::Painter,
|
||||||
|
rect: egui::Rect,
|
||||||
|
corners: [panes::CornerTypes; 4],
|
||||||
|
) {
|
||||||
|
let mut points: Vec<Pos2> = Vec::new();
|
||||||
let left = rect.left() + PANE_GAP;
|
let left = rect.left() + PANE_GAP;
|
||||||
let right = rect.right() - PANE_GAP;
|
let right = rect.right() - PANE_GAP;
|
||||||
let bottom = rect.bottom() - PANE_GAP;
|
let bottom = rect.bottom() - PANE_GAP;
|
||||||
let top = rect.top() + PANE_GAP;
|
let top = rect.top() + PANE_GAP;
|
||||||
let x1 = left + CORNER_CUT - PANE_GAP;
|
// let x1 = left + CORNER_CUT - PANE_GAP;
|
||||||
let x2 = right - CORNER_CUT + PANE_GAP;
|
// let x2 = right - CORNER_CUT + PANE_GAP;
|
||||||
let y1 = top + CORNER_CUT - PANE_GAP;
|
// let y1 = top + CORNER_CUT - PANE_GAP;
|
||||||
let y2 = bottom - CORNER_CUT + PANE_GAP;
|
// let y2 = bottom - CORNER_CUT + PANE_GAP;
|
||||||
|
|
||||||
let points = [
|
points.append(add_Pos2(
|
||||||
egui::Pos2 { x: x1, y: top },
|
Vec2 { x: left, y: top },
|
||||||
egui::Pos2 { x: x2, y: top },
|
mult_Pos2(CORNER_CUT, &mut get_corner_points(corners[0]).to_vec()),
|
||||||
egui::Pos2 { x: right, y: y1 },
|
));
|
||||||
egui::Pos2 { x: right, y: y2 },
|
|
||||||
egui::Pos2 { x: x2, y: bottom },
|
|
||||||
egui::Pos2 { x: x1, y: bottom },
|
|
||||||
egui::Pos2 { x: left, y: y2 },
|
|
||||||
egui::Pos2 { x: left, y: y1 },
|
|
||||||
];
|
|
||||||
|
|
||||||
let filled_polygon = Shape::convex_polygon(
|
points.append(add_Pos2(
|
||||||
points.to_vec(),
|
Vec2 { x: right, y: top },
|
||||||
BACKGROUND_2,
|
mult_Pos2(
|
||||||
egui::Stroke::new(0.5, TEXT_COLOR),
|
CORNER_CUT,
|
||||||
);
|
rotate_90(&mut get_corner_points(corners[1]).to_vec()),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
points.append(add_Pos2(
|
||||||
|
Vec2 {
|
||||||
|
x: right,
|
||||||
|
y: bottom,
|
||||||
|
},
|
||||||
|
mult_Pos2(
|
||||||
|
CORNER_CUT,
|
||||||
|
rotate_180(&mut get_corner_points(corners[2]).to_vec()),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
points.append(add_Pos2(
|
||||||
|
Vec2 { x: left, y: bottom },
|
||||||
|
mult_Pos2(
|
||||||
|
CORNER_CUT,
|
||||||
|
rotate_270(&mut get_corner_points(corners[3]).to_vec()),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
|
||||||
|
let filled_polygon =
|
||||||
|
Shape::convex_polygon(points, BACKGROUND_2, egui::Stroke::new(0.5, TEXT_COLOR));
|
||||||
|
|
||||||
painter.add(filled_polygon);
|
painter.add(filled_polygon);
|
||||||
// painter.rect_filled(rect, 0.0, Color32::RED);
|
|
||||||
// painter.rect_stroke(rect, 0.0, (1.0, Color32::BLACK));
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn draw_polygon(ui: &mut egui::Ui, points: &[Pos2], fill_color: egui::Color32, stroke: ) {
|
|
||||||
// if points.len() < 3 {
|
|
||||||
// return; // Need at least 3 points for a polygon
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Create the filled polygon
|
|
||||||
// let filled_polygon = Shape::convex_polygon(
|
|
||||||
// points.to_vec(),
|
|
||||||
// fill_color,
|
|
||||||
// Stroke::new(0.0, fill_color), // No stroke for fill
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // Create the outline
|
|
||||||
// let outline = Shape::line(
|
|
||||||
// points.iter().chain(std::iter::once(&points[0])).cloned().collect(),
|
|
||||||
// Stroke::new(stroke_width, outline_color),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // Get the painter and draw both shapes
|
|
||||||
// let painter = ui.painter();
|
|
||||||
// painter.add(filled_polygon);
|
|
||||||
// painter.add(outline);
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn winconfig() -> PaneConfig {
|
|
||||||
PaneConfig::new("root")
|
|
||||||
.with_split(SplitDirection::Horizontal, 0.5)
|
|
||||||
.with_callback(|painter: &egui::Painter, rect: egui::Rect| background_render(painter, rect))
|
|
||||||
.with_children(vec![
|
|
||||||
PaneConfig::new("left")
|
|
||||||
.with_split(SplitDirection::Vertical, 0.5)
|
|
||||||
.with_children(vec![
|
|
||||||
PaneConfig::new("left_top").with_callback(
|
|
||||||
|painter: &egui::Painter, rect: egui::Rect| {
|
|
||||||
background_render(painter, rect)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PaneConfig::new("left_bottom")
|
|
||||||
// .with_split(SplitDirection::Horizontal, 0.5)
|
|
||||||
.with_callback(|painter: &egui::Painter, rect: egui::Rect| {
|
|
||||||
background_render(painter, rect)
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
PaneConfig::new("right")
|
|
||||||
.with_split(SplitDirection::Vertical, 0.5)
|
|
||||||
.with_callback(|painter: &egui::Painter, rect: egui::Rect| {
|
|
||||||
background_render(painter, rect)
|
|
||||||
})
|
|
||||||
.with_children(vec![
|
|
||||||
PaneConfig::new("right_top")
|
|
||||||
.with_split(SplitDirection::Horizontal, 0.5)
|
|
||||||
.with_children(vec![
|
|
||||||
PaneConfig::new("right_top_1").with_callback(
|
|
||||||
|painter: &egui::Painter, rect: egui::Rect| {
|
|
||||||
background_render(painter, rect)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
PaneConfig::new("right_top_2").with_callback(
|
|
||||||
|painter: &egui::Painter, rect: egui::Rect| {
|
|
||||||
background_render(painter, rect)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
PaneConfig::new("right_bottom").with_callback(
|
|
||||||
|painter: &egui::Painter, rect: egui::Rect| {
|
|
||||||
background_render(painter, rect)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]),
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_password_viewer(
|
pub fn update_password_viewer(
|
||||||
@@ -131,7 +140,7 @@ pub fn update_password_viewer(
|
|||||||
ctx: &egui::Context,
|
ctx: &egui::Context,
|
||||||
frame: &mut eframe::Frame,
|
frame: &mut eframe::Frame,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
winconfig: PaneRenderer,
|
winconfig: &mut PaneRenderer,
|
||||||
) {
|
) {
|
||||||
let rect: egui::Rect = ui.available_rect_before_wrap();
|
let rect: egui::Rect = ui.available_rect_before_wrap();
|
||||||
// let ctx: cur_context = cur_context {
|
// let ctx: cur_context = cur_context {
|
||||||
@@ -153,7 +162,7 @@ pub fn update_password_viewer(
|
|||||||
);
|
);
|
||||||
|
|
||||||
dots(painter, ui.clip_rect());
|
dots(painter, ui.clip_rect());
|
||||||
winconfig.render(painter, rect);
|
winconfig.render(painter, &rect);
|
||||||
paint_password_circle(state, ctx, frame, ui, center, painter);
|
paint_password_circle(state, ctx, frame, ui, center, painter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,6 +268,8 @@ fn paint_password_circle(
|
|||||||
last_pos = pos;
|
last_pos = pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.request_repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_windows(
|
fn paint_windows(
|
||||||
@@ -277,5 +288,3 @@ fn paint_windows(
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_window(painter: &egui::Painter, width: f32, height: f32, x: f32, y: f32) {}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user