interface developing has started
Some checks failed
gitea/Frida/pipeline/head There was a failure building this commit
Some checks failed
gitea/Frida/pipeline/head There was a failure building this commit
modified: Cargo.lock modified: Cargo.toml modified: src/gui.rs new file: src/toggle_switch.rs
This commit is contained in:
parent
217d5a0587
commit
034bbbac7f
164
Cargo.lock
generated
164
Cargo.lock
generated
@ -60,9 +60,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_macos"
|
||||
version = "0.17.3"
|
||||
version = "0.17.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49509c722e8da39e6c569f7d13ec51620208988913e738abbc67e3c65f06e6d5"
|
||||
checksum = "bfc6c1ecd82053d127961ad80a8beaa6004fb851a3a5b96506d7a6bd462403f6"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer",
|
||||
@ -106,9 +106,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_winit"
|
||||
version = "0.22.3"
|
||||
version = "0.22.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9987e852fe7e4e5a493f8c8af0b729b47da2750f0dea10a4c8984fe1117ebaec"
|
||||
checksum = "aea3522719f1c44564d03e9469a8e2f3a98b3a8a880bd66d0789c6b9c4a669dd"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_macos",
|
||||
@ -885,6 +885,36 @@ dependencies = [
|
||||
"error-code",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"block",
|
||||
"cocoa-foundation",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cocoa-foundation"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"block",
|
||||
"core-foundation 0.9.4",
|
||||
"core-graphics-types",
|
||||
"libc",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
@ -1193,6 +1223,27 @@ dependencies = [
|
||||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dispatch"
|
||||
version = "0.2.0"
|
||||
@ -1343,6 +1394,15 @@ dependencies = [
|
||||
"resvg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "egui_file"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31e8280f9aea0f814013815071aebcf5c341e1d5420b381d3b0c1e3c42604d2"
|
||||
dependencies = [
|
||||
"egui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "egui_glow"
|
||||
version = "0.29.1"
|
||||
@ -1360,6 +1420,19 @@ dependencies = [
|
||||
"winit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "egui_logger"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e0d940e9a0f56a2fda347cafdd42513136ab946ca57febbc5e3c6faf77f7824"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"egui",
|
||||
"hashbrown 0.15.0",
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ehttp"
|
||||
version = "0.5.0"
|
||||
@ -1559,6 +1632,12 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.5.0"
|
||||
@ -1607,8 +1686,11 @@ dependencies = [
|
||||
"clap",
|
||||
"console-subscriber",
|
||||
"crossbeam-channel",
|
||||
"dirs",
|
||||
"eframe",
|
||||
"egui_extras",
|
||||
"egui_file",
|
||||
"egui_logger",
|
||||
"env_logger",
|
||||
"futures",
|
||||
"generic-array",
|
||||
@ -1627,6 +1709,7 @@ dependencies = [
|
||||
"socket2 0.4.10",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tray-item",
|
||||
"tun2",
|
||||
"x25519-dalek",
|
||||
]
|
||||
@ -1983,6 +2066,11 @@ name = "hashbrown"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hassle-rs"
|
||||
@ -2734,6 +2822,17 @@ dependencies = [
|
||||
"malloc_buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-foundation"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||
dependencies = [
|
||||
"block",
|
||||
"objc",
|
||||
"objc_id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-sys"
|
||||
version = "0.3.5"
|
||||
@ -2937,6 +3036,15 @@ dependencies = [
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_id"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||
dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.5"
|
||||
@ -2958,6 +3066,12 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "orbclient"
|
||||
version = "0.3.48"
|
||||
@ -3007,6 +3121,12 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "padlock"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c10569378a1dacd9f30dbe7ae49e054d2c45dc2f8ee49899903e09c3924e8b6f"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.1"
|
||||
@ -3349,6 +3469,17 @@ dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.0"
|
||||
@ -4197,6 +4328,22 @@ dependencies = [
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tray-item"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59d4bd406170690dc30eabb3badc67a085beaf9b2c3b1923afcc9c26a2191353"
|
||||
dependencies = [
|
||||
"cocoa",
|
||||
"core-graphics",
|
||||
"libc",
|
||||
"objc",
|
||||
"objc-foundation",
|
||||
"objc_id",
|
||||
"padlock",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.5"
|
||||
@ -4917,6 +5064,15 @@ dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||
dependencies = [
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
|
@ -52,9 +52,13 @@ network-interface = "2.0.0"
|
||||
[target.'cfg(target_os="windows")'.dependencies]
|
||||
eframe = { version = "0.29.1", features = ["wgpu"] }
|
||||
egui_extras = { version = "0.29.1", features = ["all_loaders"] }
|
||||
egui_file = "0.19"
|
||||
dirs = "5.0.1"
|
||||
egui_logger = "0.6.1"
|
||||
tray-item = "0.10.0"
|
||||
|
||||
[target.'cfg(target_os="android")'.dependencies]
|
||||
jni = "^0.20"
|
||||
robusta_jni = "0.2.2"
|
||||
nonblock = "0.2.0"
|
||||
log4rs = "1.3.0"
|
||||
log4rs = "1.3.0"
|
197
src/gui.rs
197
src/gui.rs
@ -1,22 +1,43 @@
|
||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
||||
|
||||
use eframe::egui::{self, Frame, Label, Spacing, Vec2};
|
||||
use eframe::egui::{self, Context, Frame, Label, ScrollArea, Spacing, Vec2};
|
||||
use egui_file::FileDialog;
|
||||
use std::{
|
||||
ffi::OsStr,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use egui_extras::{Column, TableBuilder};
|
||||
use log::{info, error};
|
||||
use crate::config::ClientConfiguration;
|
||||
use log::LevelFilter;
|
||||
use env_logger::Builder;
|
||||
|
||||
mod toggle_switch;
|
||||
mod config;
|
||||
|
||||
fn main() -> eframe::Result {
|
||||
egui_logger::builder().init().unwrap();
|
||||
|
||||
let options = eframe::NativeOptions {
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size([320.0, 240.0]),
|
||||
viewport: egui::ViewportBuilder::default().with_inner_size([640.0, 480.0]),
|
||||
..Default::default()
|
||||
};
|
||||
let mut hh = dirs::home_dir().unwrap();
|
||||
hh.push(".frida");
|
||||
let cfgs = std::fs::read_dir(hh).unwrap();
|
||||
let mut cv = Vec::new();
|
||||
for path in cfgs {
|
||||
cv.push(path.unwrap().path());
|
||||
}
|
||||
eframe::run_native(
|
||||
"Frida",
|
||||
options,
|
||||
Box::new(|cc| {
|
||||
Ok(Box::<App>::default())
|
||||
Ok(Box::new(App::new(cv)))
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
enum AppScreens {
|
||||
@ -26,14 +47,16 @@ enum AppScreens {
|
||||
|
||||
struct App {
|
||||
screen: AppScreens,
|
||||
configs: Configs
|
||||
configs: Configs,
|
||||
logs: Logs,
|
||||
}
|
||||
|
||||
impl Default for App {
|
||||
fn default() -> Self {
|
||||
impl App {
|
||||
fn new(cfgs: Vec<PathBuf>) -> Self {
|
||||
Self {
|
||||
screen: AppScreens::Configs,
|
||||
configs: Configs::default()
|
||||
configs: Configs::new(cfgs),
|
||||
logs: Logs::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -48,73 +71,171 @@ impl eframe::App for App {
|
||||
ui.separator();
|
||||
match self.screen {
|
||||
AppScreens::Configs => {
|
||||
self.configs.ui(ui);
|
||||
self.configs.ui(ui, ctx);
|
||||
}
|
||||
AppScreens::Log => {
|
||||
|
||||
self.logs.ui(ui, ctx);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "serde", serde(default))]
|
||||
#[derive(PartialEq)]
|
||||
struct Configs {
|
||||
num: u32,
|
||||
btn_status: bool,
|
||||
struct Logs {
|
||||
}
|
||||
|
||||
impl Default for Configs {
|
||||
impl Default for Logs {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
num: 32,
|
||||
btn_status: true
|
||||
}
|
||||
Self{}
|
||||
}
|
||||
}
|
||||
|
||||
impl Logs {
|
||||
fn ui(&mut self, ui: &mut egui::Ui, ctx: &Context) {
|
||||
egui::CentralPanel::default()
|
||||
.show_inside(ui, |ui| {
|
||||
egui_logger::logger_ui().show(ui);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
#[cfg_attr(feature = "serde", serde(default))]
|
||||
#[derive(Debug)]
|
||||
struct Configs {
|
||||
num: u32,
|
||||
btn_status: bool,
|
||||
open_config_dialog: Option<FileDialog>,
|
||||
cfgs: Vec<PathBuf>,
|
||||
selected_cfg: Option<(ClientConfiguration, String)>
|
||||
}
|
||||
|
||||
impl Configs {
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
fn new(cfgs: Vec<PathBuf>) -> Self {
|
||||
Self {
|
||||
num: 32,
|
||||
btn_status: false,
|
||||
open_config_dialog: None,
|
||||
cfgs,
|
||||
selected_cfg: None
|
||||
}
|
||||
}
|
||||
|
||||
fn ui(&mut self, ui: &mut egui::Ui, ctx: &Context) {
|
||||
let Self {
|
||||
num,
|
||||
btn_status
|
||||
btn_status,
|
||||
open_config_dialog,
|
||||
cfgs,
|
||||
selected_cfg
|
||||
} = self;
|
||||
|
||||
egui::SidePanel::left("clist")
|
||||
.resizable(false)
|
||||
.exact_width(150.0)
|
||||
.show_inside(ui, |ui| {
|
||||
|
||||
ScrollArea::vertical()
|
||||
.auto_shrink(false)
|
||||
.show(ui, |ui| {
|
||||
ui.set_width(ui.available_width());
|
||||
self.cfgs.iter().for_each(|f| {
|
||||
let filename = f.file_name().unwrap().to_str().unwrap();
|
||||
let mut b = egui::Button::new(filename);
|
||||
if self.selected_cfg.is_some() && self.selected_cfg.as_ref().unwrap().1 == filename.to_string() {
|
||||
b = b.fill(egui::Color32::LIGHT_BLUE);
|
||||
}
|
||||
let e = ui.add_sized(
|
||||
Vec2::new(ui.available_width(), 0.0),
|
||||
b,
|
||||
);
|
||||
if e.clicked() {
|
||||
let data = std::fs::read(f.clone());
|
||||
let cfg_raw = &String::from_utf8(data.unwrap()).unwrap();
|
||||
let config: ClientConfiguration = serde_yaml::from_str(cfg_raw).expect("Bad client config file structure");
|
||||
self.selected_cfg = Some((config, filename.to_string()));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
egui::CentralPanel::default()
|
||||
.show_inside(ui, |ui| {
|
||||
ui.spacing_mut().item_spacing.y = 20.0;
|
||||
|
||||
if self.selected_cfg.is_none() { return; }
|
||||
|
||||
let cfg = &self.selected_cfg.as_ref().unwrap().0;
|
||||
|
||||
ui.group(|ui| {
|
||||
ui.spacing_mut().item_spacing.y = 5.0;
|
||||
ui.set_width(ui.available_width());
|
||||
ui.label("Interface:");
|
||||
ui.label("Status:");
|
||||
ui.label("Public key:");
|
||||
ui.label("Address:");
|
||||
if ui.add_visible(self.btn_status, egui::Button::new("Activate")).clicked() {
|
||||
self.btn_status = false;
|
||||
};
|
||||
if ui.add_visible(!self.btn_status, egui::Button::new("Deactivate")).clicked() {
|
||||
self.btn_status = true;
|
||||
}
|
||||
ui.label(format!("Interface: {}", &self.selected_cfg.as_ref().unwrap().1));
|
||||
ui.label("Status: inactive");
|
||||
ui.label(format!("Public key: {}", &cfg.client.public_key));
|
||||
ui.label(format!("Address: {}", &cfg.client.address));
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Activate: ");
|
||||
ui.add(crate::toggle_switch::toggle(&mut self.btn_status));
|
||||
});
|
||||
});
|
||||
|
||||
ui.group(|ui| {
|
||||
ui.spacing_mut().item_spacing.y = 5.0;
|
||||
ui.set_width(ui.available_width());
|
||||
ui.label("Public key:");
|
||||
ui.label("Endpoint:");
|
||||
ui.label(format!("Public key: {}", &cfg.server.public_key));
|
||||
ui.label(format!("Endpoint: {}", &cfg.server.endpoint));
|
||||
ui.label(format!("Keepalive: {}", &cfg.server.keepalive));
|
||||
});
|
||||
});
|
||||
|
||||
egui::TopBottomPanel::bottom("btns")
|
||||
.resizable(false)
|
||||
.show_inside(ui, |ui| {
|
||||
ui.add_space(10.0);
|
||||
ui.horizontal(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 10.0;
|
||||
|
||||
if ui.button("Add config").clicked() {
|
||||
let filter = Box::new({
|
||||
let ext = Some(OsStr::new("yaml"));
|
||||
move |path: &Path| -> bool { path.extension() == ext }
|
||||
});
|
||||
let mut dialog = FileDialog::open_file(None).show_files_filter(filter);
|
||||
dialog.open();
|
||||
|
||||
self.open_config_dialog = Some(dialog);
|
||||
}
|
||||
|
||||
if let Some(dialog) = &mut self.open_config_dialog {
|
||||
if dialog.show(ctx).selected() {
|
||||
if let Some(file) = dialog.path() {
|
||||
if let Some(home) = dirs::home_dir() {
|
||||
let mut h = home.clone();
|
||||
h.push(".frida");
|
||||
std::fs::create_dir_all(&h);
|
||||
h.push(file.file_name().unwrap());
|
||||
std::fs::copy(file, &h);
|
||||
|
||||
self.cfgs.push(h);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ui.button("Remove selected").clicked() {
|
||||
let path = &self.selected_cfg.as_ref().unwrap().1;
|
||||
if let Ok(r) = std::fs::remove_file(path) {
|
||||
error!("FUCK");
|
||||
for i in 0..self.cfgs.len() {
|
||||
error!("AA {:?}", path);
|
||||
if path == self.cfgs[i].file_name().unwrap().to_str().unwrap() {
|
||||
self.cfgs.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.selected_cfg = None;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
46
src/toggle_switch.rs
Normal file
46
src/toggle_switch.rs
Normal file
@ -0,0 +1,46 @@
|
||||
/// iOS-style toggle switch:
|
||||
///
|
||||
/// ``` text
|
||||
/// _____________
|
||||
/// / /.....\
|
||||
/// | |.......|
|
||||
/// \_______\_____/
|
||||
/// ```
|
||||
///
|
||||
/// ## Example:
|
||||
/// ``` ignore
|
||||
/// toggle_ui(ui, &mut my_bool);
|
||||
/// ```
|
||||
|
||||
use eframe::egui;
|
||||
|
||||
fn toggle_ui(ui: &mut egui::Ui, on: &mut bool) -> egui::Response {
|
||||
let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0, 1.0);
|
||||
let (rect, mut response) = ui.allocate_exact_size(desired_size, egui::Sense::click());
|
||||
if response.clicked() {
|
||||
*on = !*on;
|
||||
response.mark_changed();
|
||||
}
|
||||
response.widget_info(|| {
|
||||
egui::WidgetInfo::selected(egui::WidgetType::Checkbox, ui.is_enabled(), *on, "")
|
||||
});
|
||||
|
||||
if ui.is_rect_visible(rect) {
|
||||
let how_on = ui.ctx().animate_bool_responsive(response.id, *on);
|
||||
let visuals = ui.style().interact_selectable(&response, *on);
|
||||
let rect = rect.expand(visuals.expansion);
|
||||
let radius = 0.5 * rect.height();
|
||||
ui.painter()
|
||||
.rect(rect, radius, visuals.bg_fill, visuals.bg_stroke);
|
||||
let circle_x = egui::lerp((rect.left() + radius)..=(rect.right() - radius), how_on);
|
||||
let center = egui::pos2(circle_x, rect.center().y);
|
||||
ui.painter()
|
||||
.circle(center, 0.75 * radius, visuals.bg_fill, visuals.fg_stroke);
|
||||
}
|
||||
|
||||
response
|
||||
}
|
||||
|
||||
pub fn toggle(on: &mut bool) -> impl egui::Widget + '_ {
|
||||
move |ui: &mut egui::Ui| toggle_ui(ui, on)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user