mirror of
https://github.com/Astatin3/raylock.git
synced 2026-06-09 00:28:00 -06:00
Add SciFi
This commit is contained in:
+2
-5
@@ -6,8 +6,5 @@ edition = "2021"
|
||||
[dependencies]
|
||||
eframe = "0.28"
|
||||
egui = "0.28"
|
||||
portable-pty = "0.8.1"
|
||||
termwiz = "0.22.0"
|
||||
vte = "0.13.0"
|
||||
egui-terminal = { git = "https://github.com/Quinntyx/egui-terminal" }
|
||||
ecolor = "0.29.1"
|
||||
rand = "0.8.5"
|
||||
serde = "1.0.214"
|
||||
|
||||
@@ -5,8 +5,9 @@ Unfortunatly this is not the most secure desktop locker, as it involves using sw
|
||||
|
||||
```
|
||||
# Add this to your sway config:
|
||||
for_window [title="^raylock$"] sticky enable, floating enable, resize set 1920 px 1080 px, title_format "", border pixel none
|
||||
for_window [title="^raylock$"] sticky enable, fullscreen
|
||||
mode "lock" {
|
||||
bindsym $mod+Shift+q exec true
|
||||
bindsym XF86MonBrightnessUp exec brightnessctl s +5%
|
||||
bindsym XF86MonBrightnessDown exec brightnessctl s 5%-
|
||||
}
|
||||
```
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,42 @@
|
||||
use crate::structs;
|
||||
use egui::{Color32, Stroke};
|
||||
use std::f32::consts::PI;
|
||||
|
||||
// pub const windows: PaneSplit =
|
||||
// Pane::new(SplitHorisontal).new_hsplit(Pane::new(Temp1), Pane::new(Temp2));
|
||||
|
||||
pub const TEXT_COLOR: Color32 = Color32::from_rgb(255, 255, 255);
|
||||
pub const BACKGROUND_2: Color32 = Color32::from_rgba_premultiplied(10, 10, 10, 230);
|
||||
|
||||
pub const LOGIN_CIRCLE_RADIUS: f32 = 50.;
|
||||
pub const LOGIN_SUBCIRCLE_START_ANG: f32 = -PI / 4.;
|
||||
|
||||
pub const LOGIN_SUBCIRCLE_RADIUS: f32 = 4.;
|
||||
pub const LOGIN_SUBCIRCLE_COLOR: Color32 = Color32::TRANSPARENT;
|
||||
pub const LOGIN_SUBCIRCLE_STROKE: Stroke = Stroke {
|
||||
width: 2.0,
|
||||
color: Color32::from_rgb(255, 255, 255),
|
||||
};
|
||||
pub const LOGIN_CIRCLE_LINE_STROKE: Stroke = Stroke {
|
||||
width: 2.0,
|
||||
color: TEXT_COLOR,
|
||||
};
|
||||
pub const LOGIN_FAIL_COLOR: Color32 = Color32::from_rgb(184, 41, 11);
|
||||
pub const LOGIN_FAIL_CIRCLE_STROKE: Stroke = Stroke {
|
||||
width: 5.,
|
||||
color: LOGIN_FAIL_COLOR,
|
||||
};
|
||||
pub const LOGIN_FAIL_COUNT_CIRCLE_RADIUS: f32 = 15.;
|
||||
pub const LOGIN_FAIL_COUNT_CIRCLE_COLOR: Color32 = Color32::TRANSPARENT;
|
||||
pub const LOGIN_FAIL_COUNT_CIRCLE_STROKE: Stroke = Stroke {
|
||||
width: 2.,
|
||||
color: LOGIN_FAIL_COLOR,
|
||||
};
|
||||
|
||||
pub const DOTS_SPACING: f32 = 25.;
|
||||
pub const DOTS_RAD: f32 = 0.7;
|
||||
pub const DOTS_COLOR: Color32 = Color32::from_rgb(255, 255, 255);
|
||||
// pub const DOTS_STROKE: Stroke = Stroke {0., DOTS_COLOR};
|
||||
|
||||
pub const CORNER_CUT: f32 = LOGIN_CIRCLE_RADIUS * 1.41421356237;
|
||||
pub const PANE_GAP: f32 = 6.;
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
use egui::Key;
|
||||
use std::fs::{exists, File};
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
use std::thread;
|
||||
@@ -9,18 +9,18 @@ const LOCK_FILEPATH: &str = "/tmp/.raylock.lock";
|
||||
pub fn sway_lock_input() {
|
||||
thread::spawn(move || {
|
||||
let _ = Command::new("swaymsg").args(["mode", "lock"]).spawn();
|
||||
let _ = Command::new("swaymsg")
|
||||
.args(["input", "type:touchpad", "events", "disabled"])
|
||||
.spawn();
|
||||
// let _ = Command::new("swaymsg")
|
||||
// .args(["input", "type:touchpad", "events", "disabled"])
|
||||
// .spawn();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn sway_unlock_input() {
|
||||
thread::spawn(move || {
|
||||
let _ = Command::new("swaymsg").args(["mode", "default"]).spawn();
|
||||
let _ = Command::new("swaymsg")
|
||||
.args(["input", "type:touchpad", "events", "enabled"])
|
||||
.spawn();
|
||||
// let _ = Command::new("swaymsg")
|
||||
// .args(["input", "type:touchpad", "events", "enabled"])
|
||||
// .spawn();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+37
-33
@@ -1,7 +1,6 @@
|
||||
use eframe::{egui, App};
|
||||
use egui::FontFamily;
|
||||
use egui::Key;
|
||||
use egui_terminal;
|
||||
use input::is_locked;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
@@ -9,6 +8,7 @@ use std::process::{Command, Stdio};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use structs::{PaneConfig, PaneRenderer, SplitDirection};
|
||||
|
||||
// use egui::epaint::text::{FontInsert, InsertFontFamily};
|
||||
|
||||
@@ -16,54 +16,55 @@ use eframe::CreationContext;
|
||||
use egui::ecolor::Color32;
|
||||
use egui::FontId;
|
||||
use egui::Stroke;
|
||||
use egui_terminal::prelude::*;
|
||||
use egui_terminal::render::CursorType;
|
||||
// use egui_terminal::prelude::*;
|
||||
// use egui_terminal::render::CursorType;
|
||||
|
||||
use egui::ecolor::HexColor;
|
||||
|
||||
mod configs;
|
||||
mod input;
|
||||
mod splitter;
|
||||
mod structs;
|
||||
mod ui;
|
||||
|
||||
// Demonstrates how to add a font to the existing ones
|
||||
fn add_font(ctx: &egui::Context) {
|
||||
// Start with the default fonts (we will be adding to them rather than replacing them).
|
||||
let mut fonts = egui::FontDefinitions::default();
|
||||
// fn add_font(ctx: &egui::Context) {
|
||||
// // Start with the default fonts (we will be adding to them rather than replacing them).
|
||||
// let mut fonts = egui::FontDefinitions::default();
|
||||
|
||||
// Install my own font (maybe supporting non-latin characters).
|
||||
// .ttf and .otf files supported.
|
||||
fonts.font_data.insert(
|
||||
"my_font".to_owned(),
|
||||
egui::FontData::from_static(include_bytes!(
|
||||
"/home/astatin3/.fonts/UbuntuMono/UbuntuMonoNerdFontMono-Regular.ttf"
|
||||
)),
|
||||
);
|
||||
// // Install my own font (maybe supporting non-latin characters).
|
||||
// // .ttf and .otf files supported.
|
||||
// fonts.font_data.insert(
|
||||
// "my_font".to_owned(),
|
||||
// egui::FontData::from_static(include_bytes!(
|
||||
// "/home/astatin3/.fonts/UbuntuMono/UbuntuMonoNerdFontMono-Regular.ttf"
|
||||
// )),
|
||||
// );
|
||||
|
||||
// Put my font first (highest priority) for proportional text:
|
||||
// fonts
|
||||
// .families
|
||||
// .entry(egui::FontFamily::Proportional)
|
||||
// .or_default()
|
||||
// .insert(0, "my_font".to_owned());
|
||||
// // Put my font first (highest priority) for proportional text:
|
||||
// // fonts
|
||||
// // .families
|
||||
// // .entry(egui::FontFamily::Proportional)
|
||||
// // .or_default()
|
||||
// // .insert(0, "my_font".to_owned());
|
||||
|
||||
// Put my font as last fallback for monospace:
|
||||
fonts
|
||||
.families
|
||||
.entry(egui::FontFamily::Monospace)
|
||||
.or_default()
|
||||
.push("my_font".to_owned());
|
||||
// // Put my font as last fallback for monospace:
|
||||
// fonts
|
||||
// .families
|
||||
// .entry(egui::FontFamily::Monospace)
|
||||
// .or_default()
|
||||
// .push("my_font".to_owned());
|
||||
|
||||
// Tell egui to use these fonts:
|
||||
ctx.set_fonts(fonts);
|
||||
}
|
||||
// // Tell egui to use these fonts:
|
||||
// ctx.set_fonts(fonts);
|
||||
// }
|
||||
|
||||
use splitter::Splitter;
|
||||
|
||||
#[derive(Default)]
|
||||
struct ExampleApp {
|
||||
auth_state: Arc<Mutex<structs::AuthState>>,
|
||||
terminals: HashMap<String, TermHandler>,
|
||||
// terminals: HashMap<String, TermHandler>,
|
||||
}
|
||||
|
||||
impl ExampleApp {
|
||||
@@ -101,6 +102,9 @@ impl eframe::App for ExampleApp {
|
||||
|
||||
let mut state = self.auth_state.lock().unwrap();
|
||||
//ctx.set_pixels_per_point(1.5);
|
||||
let config = ui::winconfig();
|
||||
|
||||
let pane_renderer = PaneRenderer::new(config);
|
||||
|
||||
if ctx.input(|i| i.events.len() > 0) {
|
||||
ctx.input(|i| {
|
||||
@@ -177,7 +181,7 @@ impl eframe::App for ExampleApp {
|
||||
// },
|
||||
// );
|
||||
|
||||
ui::update_password_viewer(state, ctx, _frame, ui);
|
||||
ui::update_password_viewer(state, ctx, _frame, ui, pane_renderer);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -228,7 +232,7 @@ fn main() -> eframe::Result<()> {
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
});
|
||||
|
||||
let mut map = HashMap::new();
|
||||
// let mut map = HashMap::new();
|
||||
// map.insert(String::from("0"), TermHandler::new_from_str("btop"));
|
||||
// map.insert(String::from("1h-0"), TermHandler::new_from_str("nvitop"));
|
||||
// map.insert(String::from("1h-1"), TermHandler::new_from_str("neofetch"));
|
||||
@@ -247,7 +251,7 @@ fn main() -> eframe::Result<()> {
|
||||
Box::new(|_| {
|
||||
Ok(Box::<ExampleApp>::new(ExampleApp {
|
||||
auth_state: state,
|
||||
terminals: map,
|
||||
// terminals: map,
|
||||
}))
|
||||
}),
|
||||
)
|
||||
|
||||
-190
@@ -1,190 +0,0 @@
|
||||
/// https://gist.github.com/mkalte666/f9a982be0ac0276080d3434ab9ea4655
|
||||
use std::hash::Hash;
|
||||
|
||||
use egui::{CursorIcon, Id, Layout, Pos2, Rect, Rounding, Sense, Ui, Vec2};
|
||||
|
||||
/// An axis that a Splitter can use
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum SplitterAxis {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
/// The internal data used by a splitter. Stored into memory
|
||||
#[derive(Debug, Clone)]
|
||||
struct SplitterData {
|
||||
axis: SplitterAxis,
|
||||
pos: f32,
|
||||
min_size: f32,
|
||||
}
|
||||
|
||||
/// Splits a ui in half, using a draggable separator in the middle.
|
||||
///
|
||||
pub struct Splitter {
|
||||
id: Id,
|
||||
data: SplitterData,
|
||||
}
|
||||
impl Splitter {
|
||||
/// Create a new Splitter
|
||||
pub fn new(id_source: impl Hash, axis: SplitterAxis) -> Self {
|
||||
Self {
|
||||
id: Id::new(id_source),
|
||||
data: SplitterData {
|
||||
axis,
|
||||
pos: 0.5,
|
||||
min_size: 0.0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the minimum allowed size for the area
|
||||
pub fn min_size(mut self, points: f32) -> Self {
|
||||
self.data.min_size = points;
|
||||
self
|
||||
}
|
||||
|
||||
/// Thes the default position of the splitter separator. Usually it sits in the center, this moves it around.
|
||||
pub fn default_pos(mut self, pos: f32) -> Self {
|
||||
self.data.pos = pos;
|
||||
self
|
||||
}
|
||||
|
||||
/// Show the splitter and fill it with content.
|
||||
///
|
||||
/// ```
|
||||
/// Splitter::new("some_plot_split", SplitterAxis::Vertical)
|
||||
/// .min_size(250.0)
|
||||
/// .default_pos(2.0 / 3.0)
|
||||
/// .show(ui, |ui_a, ui_b| {
|
||||
/// Plot::new("plot_a")
|
||||
/// .legend(Legend::default())
|
||||
/// .x_axis_formatter(log_formatter)
|
||||
/// .y_axis_formatter(log_formatter)
|
||||
/// .x_axis_label("X Axis")
|
||||
/// .y_axis_label("A Axis")
|
||||
/// .link_axis("axis_link", true, false)
|
||||
/// .link_cursor("cursor_link", true, false)
|
||||
/// .show(ui_a, |plot_ui| {
|
||||
/// for line in plot_a_lines {
|
||||
/// plot_ui.line(line);
|
||||
/// }
|
||||
/// });
|
||||
///
|
||||
/// Plot::new("plot_b")
|
||||
/// .legend(Legend::default())
|
||||
/// .x_axis_formatter(log_formatter)
|
||||
/// .x_axis_label("X Axis")
|
||||
/// .y_axis_label("Y Axis")
|
||||
/// .link_axis("axis_link", true, false)
|
||||
/// .link_cursor("cursor_link", true, false)
|
||||
/// .show(ui_b, |plot_ui| {
|
||||
/// for line in plot_b_lines {
|
||||
/// plot_ui.line(line);
|
||||
/// }
|
||||
/// });
|
||||
/// });
|
||||
/// ```
|
||||
pub fn show(mut self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui, &mut Ui)) {
|
||||
let mut data = if let Some(d) = ui.memory(|mem| mem.data.get_temp(self.id)) {
|
||||
d
|
||||
} else {
|
||||
self.data.clone()
|
||||
};
|
||||
|
||||
let sep_size = 10.0;
|
||||
let sep_stroke = 2.0;
|
||||
let whole_area = ui.available_size();
|
||||
|
||||
let split_axis_size = match data.axis {
|
||||
SplitterAxis::Horizontal => whole_area.x,
|
||||
SplitterAxis::Vertical => whole_area.y,
|
||||
};
|
||||
let split_a_size = ((split_axis_size - sep_size) * data.pos);
|
||||
let split_b_size = split_axis_size - sep_size - split_a_size;
|
||||
|
||||
let child_size_a = match data.axis {
|
||||
SplitterAxis::Horizontal => Vec2::new(split_a_size, whole_area.y),
|
||||
SplitterAxis::Vertical => Vec2::new(whole_area.x, split_a_size),
|
||||
};
|
||||
|
||||
let child_size_b = match data.axis {
|
||||
SplitterAxis::Horizontal => Vec2::new(split_b_size, whole_area.y),
|
||||
SplitterAxis::Vertical => Vec2::new(whole_area.x, split_b_size),
|
||||
};
|
||||
|
||||
let child_rect_a = Rect::from_min_size(ui.next_widget_position(), child_size_a);
|
||||
let mut ui_a = ui.child_ui(child_rect_a, Layout::default(), None);
|
||||
|
||||
let sep_rect = match data.axis {
|
||||
SplitterAxis::Horizontal => Rect::from_min_size(
|
||||
Pos2::new(child_rect_a.max.x, child_rect_a.min.y),
|
||||
Vec2::new(sep_size, whole_area.y),
|
||||
),
|
||||
SplitterAxis::Vertical => Rect::from_min_size(
|
||||
Pos2::new(child_rect_a.min.x, child_rect_a.max.y),
|
||||
Vec2::new(whole_area.x, sep_size),
|
||||
),
|
||||
};
|
||||
|
||||
let resp = ui.allocate_rect(sep_rect, Sense::hover().union(Sense::click_and_drag()));
|
||||
|
||||
let sep_draw_rect = match data.axis {
|
||||
SplitterAxis::Horizontal => Rect::from_min_size(
|
||||
Pos2::new(
|
||||
sep_rect.min.x + sep_size / 2.0 - sep_stroke / 2.0,
|
||||
sep_rect.min.y,
|
||||
),
|
||||
Vec2::new(sep_stroke, sep_rect.height()),
|
||||
),
|
||||
SplitterAxis::Vertical => Rect::from_min_size(
|
||||
Pos2::new(
|
||||
sep_rect.min.x,
|
||||
sep_rect.min.y + sep_size / 2.0 - sep_stroke / 2.0,
|
||||
),
|
||||
Vec2::new(sep_rect.width(), sep_stroke),
|
||||
),
|
||||
};
|
||||
ui.painter().rect_filled(
|
||||
sep_draw_rect,
|
||||
Rounding::ZERO,
|
||||
ui.style().visuals.noninteractive().bg_stroke.color,
|
||||
);
|
||||
|
||||
let child_rect_b = match data.axis {
|
||||
SplitterAxis::Horizontal => {
|
||||
Rect::from_min_size(Pos2::new(sep_rect.max.x, sep_rect.min.y), child_size_b)
|
||||
}
|
||||
SplitterAxis::Vertical => {
|
||||
Rect::from_min_size(Pos2::new(sep_rect.min.x, sep_rect.max.y), child_size_b)
|
||||
}
|
||||
};
|
||||
let mut ui_b = ui.child_ui(child_rect_b, Layout::default(), None);
|
||||
|
||||
add_contents(&mut ui_a, &mut ui_b);
|
||||
|
||||
if resp.hovered() {
|
||||
match data.axis {
|
||||
SplitterAxis::Horizontal => ui.ctx().set_cursor_icon(CursorIcon::ResizeVertical),
|
||||
SplitterAxis::Vertical => ui.ctx().set_cursor_icon(CursorIcon::ResizeHorizontal),
|
||||
}
|
||||
}
|
||||
|
||||
if resp.dragged() {
|
||||
let delta_pos = match data.axis {
|
||||
SplitterAxis::Horizontal => resp.drag_delta().x / whole_area.x,
|
||||
SplitterAxis::Vertical => resp.drag_delta().y / whole_area.y,
|
||||
};
|
||||
|
||||
data.pos += delta_pos;
|
||||
}
|
||||
|
||||
// clip pos
|
||||
let min_pos = (data.min_size / split_axis_size).min(1.0);
|
||||
let max_pos = (1.0 - min_pos).max(0.0);
|
||||
data.pos = data.pos.max(min_pos).min(max_pos);
|
||||
|
||||
ui.memory_mut(|mem| {
|
||||
mem.data.insert_temp(self.id, data);
|
||||
})
|
||||
}
|
||||
}
|
||||
+239
@@ -1,6 +1,245 @@
|
||||
use egui::{Color32, Painter, Pos2, Rect, Vec2};
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::sync::MutexGuard;
|
||||
// use serde::
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct AuthState {
|
||||
pub password: String,
|
||||
pub to_be_submitted: bool,
|
||||
pub failed_attempts: u16,
|
||||
}
|
||||
|
||||
// pub enum windowTypes {
|
||||
// Temp1,
|
||||
// Temp2,
|
||||
|
||||
// SplitVertical,
|
||||
// SplitHorisontal,
|
||||
// }
|
||||
|
||||
// pub struct Pane {
|
||||
// pub wintype: windowTypes,
|
||||
// }
|
||||
|
||||
// pub struct PaneSplit {
|
||||
// pub wintype: windowTypes,
|
||||
// pub sub_a: Pane,
|
||||
// pub sub_b: Pane,
|
||||
// }
|
||||
|
||||
// impl Pane {
|
||||
// pub const fn new(wintype: windowTypes) -> Self {
|
||||
// Self { wintype: wintype }
|
||||
// }
|
||||
|
||||
// pub const fn new_hsplit(wintype: windowTypes, left: Pane, right: Pane) -> PaneSplit {
|
||||
// PaneSplit {
|
||||
// wintype: wintype,
|
||||
// sub_a: left,
|
||||
// sub_b: right,
|
||||
// }
|
||||
// }
|
||||
// pub const fn new_rsplit(wintype: windowTypes, wintop: Pane, bottom: Pane) -> PaneSplit {
|
||||
// PaneSplit {
|
||||
// wintype: wintype,
|
||||
// sub_a: top,
|
||||
// sub_b: bottom,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// 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,38 +1,19 @@
|
||||
use crate::configs::*;
|
||||
use crate::structs;
|
||||
use crate::structs::PaneRenderer;
|
||||
// use crate::structs::cur_context;
|
||||
// use crate::structs::windowTypes;
|
||||
|
||||
use eframe::egui;
|
||||
use egui::Color32;
|
||||
use egui::Pos2;
|
||||
use egui::Stroke;
|
||||
use egui::Shape;
|
||||
use std::f32::consts::PI;
|
||||
use structs::{PaneConfig, SplitDirection};
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::sync::MutexGuard;
|
||||
|
||||
const TEXT_COLOR: Color32 = Color32::from_rgb(255, 255, 255);
|
||||
const LOGIN_CIRCLE_RADIUS: f32 = 50.;
|
||||
const LOGIN_SUBCIRCLE_START_ANG: f32 = -PI / 4.;
|
||||
|
||||
const LOGIN_SUBCIRCLE_RADIUS: f32 = 4.;
|
||||
const LOGIN_SUBCIRCLE_COLOR: Color32 = Color32::TRANSPARENT;
|
||||
const LOGIN_SUBCIRCLE_STROKE: Stroke = Stroke {
|
||||
width: 2.0,
|
||||
color: Color32::from_rgb(255, 255, 255),
|
||||
};
|
||||
const LOGIN_CIRCLE_LINE_STROKE: Stroke = Stroke {
|
||||
width: 2.0,
|
||||
color: TEXT_COLOR,
|
||||
};
|
||||
const LOGIN_FAIL_COLOR: Color32 = Color32::from_rgb(184, 41, 11);
|
||||
const LOGIN_FAIL_CIRCLE_STROKE: Stroke = Stroke {
|
||||
width: 5.,
|
||||
color: LOGIN_FAIL_COLOR,
|
||||
};
|
||||
const LOGIN_FAIL_COUNT_CIRCLE_RADIUS: f32 = 15.;
|
||||
const LOGIN_FAIL_COUNT_CIRCLE_COLOR: Color32 = Color32::TRANSPARENT;
|
||||
const LOGIN_FAIL_COUNT_CIRCLE_STROKE: Stroke = Stroke {
|
||||
width: 2.,
|
||||
color: LOGIN_FAIL_COLOR,
|
||||
};
|
||||
|
||||
fn rot_circle(i: i16, center: Pos2, rad: f32, offset_ang: f32, ang_per_num: f32) -> Pos2 {
|
||||
center
|
||||
+ (egui::Vec2 {
|
||||
@@ -41,22 +22,170 @@ 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) {
|
||||
let left = rect.left() + PANE_GAP;
|
||||
let right = rect.right() - PANE_GAP;
|
||||
let bottom = rect.bottom() - PANE_GAP;
|
||||
let top = rect.top() + PANE_GAP;
|
||||
let x1 = left + CORNER_CUT - PANE_GAP;
|
||||
let x2 = right - CORNER_CUT + PANE_GAP;
|
||||
let y1 = top + CORNER_CUT - PANE_GAP;
|
||||
let y2 = bottom - CORNER_CUT + PANE_GAP;
|
||||
|
||||
let points = [
|
||||
egui::Pos2 { x: x1, y: top },
|
||||
egui::Pos2 { x: x2, y: top },
|
||||
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.to_vec(),
|
||||
BACKGROUND_2,
|
||||
egui::Stroke::new(0.5, TEXT_COLOR),
|
||||
);
|
||||
|
||||
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(
|
||||
wstate: MutexGuard<'_, structs::AuthState>,
|
||||
ctx: &egui::Context,
|
||||
frame: &mut eframe::Frame,
|
||||
ui: &mut egui::Ui,
|
||||
winconfig: PaneRenderer,
|
||||
) {
|
||||
let mut state = wstate;
|
||||
let rect = ui.clip_rect();
|
||||
let center = Pos2 {
|
||||
let rect: egui::Rect = ui.available_rect_before_wrap();
|
||||
// let ctx: cur_context = cur_context {
|
||||
let state: &structs::AuthState = wstate.deref();
|
||||
|
||||
let center: Pos2 = Pos2 {
|
||||
x: rect.width() / 2.,
|
||||
y: rect.height() / 2.,
|
||||
};
|
||||
let painter: &egui::Painter = ui.painter();
|
||||
|
||||
let painter = ui.painter();
|
||||
paint_windows(
|
||||
painter,
|
||||
rect.width() as f32,
|
||||
rect.height() as f32,
|
||||
0.,
|
||||
0.,
|
||||
// windows,
|
||||
);
|
||||
|
||||
// Login Circle
|
||||
dots(painter, ui.clip_rect());
|
||||
winconfig.render(painter, rect);
|
||||
paint_password_circle(state, ctx, frame, ui, center, painter);
|
||||
}
|
||||
|
||||
fn dots(painter: &egui::Painter, win_rect: egui::Rect) {
|
||||
let dots_x = win_rect.right() / DOTS_SPACING;
|
||||
let dots_y = win_rect.bottom() / DOTS_SPACING;
|
||||
for x in (-dots_x as i32 / 2)..((dots_x as i32 / 2) + 1) {
|
||||
for y in (-dots_y as i32 / 2)..((dots_y as i32 / 2) + 1) {
|
||||
painter.circle(
|
||||
Pos2 {
|
||||
x: win_rect.right() / 2. + (x as f32 * DOTS_SPACING),
|
||||
y: win_rect.bottom() / 2. + (y as f32 * DOTS_SPACING),
|
||||
},
|
||||
DOTS_RAD,
|
||||
DOTS_COLOR,
|
||||
egui::Stroke::NONE,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_password_circle(
|
||||
state: &structs::AuthState,
|
||||
|
||||
ctx: &egui::Context,
|
||||
frame: &eframe::Frame,
|
||||
ui: &egui::Ui,
|
||||
|
||||
center: egui::Pos2,
|
||||
painter: &egui::Painter,
|
||||
) {
|
||||
let len = state.password.len();
|
||||
|
||||
if state.failed_attempts > 0 {
|
||||
painter.circle(
|
||||
@@ -131,3 +260,22 @@ pub fn update_password_viewer(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_windows(
|
||||
painter: &egui::Painter,
|
||||
|
||||
width: f32,
|
||||
height: f32,
|
||||
x: f32,
|
||||
y: f32,
|
||||
// pane: structs::PaneSplit,
|
||||
) {
|
||||
// match pane.wintype {
|
||||
// windowTypes::SplitHorisontal => {
|
||||
// paint_windows(painter, width, height / 2., x, y, pane.sub_a);
|
||||
// paint_windows(painter, width, height / 2., x, y + height / 2., pane.sub_b);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
fn paint_window(painter: &egui::Painter, width: f32, height: f32, x: f32, y: f32) {}
|
||||
|
||||
Reference in New Issue
Block a user