Compare commits
No commits in common. "94bcff177eb0645b542c46919d469f3694d2b05c" and "b5b7b25dfaf2ff1976d5468826212955bc8ce0bb" have entirely different histories.
94bcff177e
...
b5b7b25dfa
|
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'workspace'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=workspace",
|
||||
"--package=workspace"
|
||||
],
|
||||
"filter": {
|
||||
"name": "workspace",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug unit tests in executable 'workspace'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"test",
|
||||
"--no-run",
|
||||
"--bin=workspace",
|
||||
"--package=workspace"
|
||||
],
|
||||
"filter": {
|
||||
"name": "workspace",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
10
Cargo.toml
10
Cargo.toml
|
|
@ -6,13 +6,5 @@ edition = "2021"
|
|||
[dependencies]
|
||||
tray-icon = "0.19.0"
|
||||
image = "0.25"
|
||||
notan = { version = "0.12.1", features = ["audio", "clipboard", "drop_files", "egui", "extra", "links", "notan_extra", "save_file", "serde", "text"] }
|
||||
notan = { version = "0.12.1", features = ["egui"] }
|
||||
anyhow = "1.0.89"
|
||||
notan_extra = "0.12.1"
|
||||
tokio = { version = "1.40.0", features = ["full"] }
|
||||
indexmap = { version = "2.6.0", features = ["serde"] }
|
||||
serde = { version = "1.0.210", features = ["derive"] }
|
||||
rsn = "0.1.0"
|
||||
known-folders = "1.2.0"
|
||||
eframe = "0.29.1"
|
||||
egui = "0.29.1"
|
||||
|
|
|
|||
224
src/main.rs
224
src/main.rs
|
|
@ -1,183 +1,61 @@
|
|||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use indexmap::IndexSet;
|
||||
use notan::{
|
||||
draw::DrawConfig,
|
||||
egui::{self, *},
|
||||
extra::FpsLimit,
|
||||
log::warn,
|
||||
prelude::*,
|
||||
Event,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::process::Command;
|
||||
use notan::draw::DrawConfig;
|
||||
use notan::egui::{self, *};
|
||||
use notan::prelude::*;
|
||||
use tray_icon::menu::MenuEventReceiver;
|
||||
use tray_icon::TrayIcon;
|
||||
use tray_icon::{
|
||||
menu::{Menu, MenuEvent, MenuEventReceiver, MenuItem, PredefinedMenuItem},
|
||||
MouseButton, TrayIcon, TrayIconBuilder, TrayIconEvent, TrayIconEventReceiver,
|
||||
menu::{Menu, MenuEvent, MenuItem, PredefinedMenuItem},
|
||||
TrayIconBuilder,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Hash, PartialEq, Eq)]
|
||||
struct LogFile {
|
||||
name: String,
|
||||
path: PathBuf,
|
||||
}
|
||||
|
||||
struct TrayData {
|
||||
#[derive(AppState)]
|
||||
struct State {
|
||||
tray_icon: Option<TrayIcon>,
|
||||
quit_i: MenuItem,
|
||||
menu_channel: MenuEventReceiver,
|
||||
tray_channel: TrayIconEventReceiver,
|
||||
}
|
||||
|
||||
impl Default for TrayData {
|
||||
fn default() -> Self {
|
||||
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/icon.png");
|
||||
|
||||
let tray_menu = Menu::new();
|
||||
|
||||
let test = MenuItem::new("Test", true, None);
|
||||
let quit_i = MenuItem::new("Quit", true, None);
|
||||
tray_menu
|
||||
.append_items(&[&test, &PredefinedMenuItem::separator(), &quit_i])
|
||||
.unwrap();
|
||||
let icon = load_icon(std::path::Path::new(path));
|
||||
|
||||
let tray_icon = Some(
|
||||
TrayIconBuilder::new()
|
||||
.with_menu_on_left_click(false)
|
||||
.with_menu(Box::new(tray_menu.clone()))
|
||||
.with_tooltip("Workspace")
|
||||
.with_icon(icon)
|
||||
.build()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let menu_channel = MenuEvent::receiver().clone();
|
||||
let tray_channel = TrayIconEvent::receiver().clone();
|
||||
TrayData {
|
||||
menu_channel,
|
||||
tray_icon,
|
||||
quit_i,
|
||||
tray_channel,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(AppState, Serialize, Deserialize)]
|
||||
struct State {
|
||||
#[serde(skip)]
|
||||
tray_data: TrayData,
|
||||
log_history: IndexSet<LogFile>,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn save(&mut self) {
|
||||
let folder = known_folders::get_known_folder_path(known_folders::KnownFolder::LocalAppData)
|
||||
.unwrap()
|
||||
.join("workspace");
|
||||
std::fs::create_dir_all(&folder).unwrap();
|
||||
std::fs::write(folder.join("data.rsn"), rsn::to_string(self)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), String> {
|
||||
#[notan_main]
|
||||
fn main() -> Result<(), String> {
|
||||
let win = WindowConfig::new()
|
||||
.set_vsync(false)
|
||||
.set_vsync(true)
|
||||
.set_lazy_loop(true)
|
||||
.set_transparent(true)
|
||||
.set_high_dpi(true);
|
||||
|
||||
notan::init_with(init)
|
||||
.add_config(win)
|
||||
.add_config(EguiConfig)
|
||||
.add_config(DrawConfig)
|
||||
.add_plugin(FpsLimit::new(60))
|
||||
.update(update)
|
||||
.event(event)
|
||||
.draw(draw)
|
||||
.build()
|
||||
}
|
||||
|
||||
fn update(app: &mut App, state: &mut State) {
|
||||
if let Ok(event) = MenuEvent::receiver().try_recv() {
|
||||
if event.id == state.tray_data.quit_i.id() {
|
||||
state.tray_data.tray_icon.take();
|
||||
if let Ok(event) = state.menu_channel.try_recv() {
|
||||
if event.id == state.quit_i.id() {
|
||||
state.tray_icon.take();
|
||||
app.exit();
|
||||
}
|
||||
println!("{event:?}");
|
||||
}
|
||||
}
|
||||
|
||||
fn event(_app: &mut App, _assets: &mut Assets, state: &mut State, evt: Event) {
|
||||
match evt {
|
||||
Event::Exit => {}
|
||||
Event::Drop(file) => {
|
||||
if file.name.ends_with(".log") {
|
||||
state.log_history.shift_insert(
|
||||
0,
|
||||
LogFile {
|
||||
name: file.name.clone(),
|
||||
path: file
|
||||
.path
|
||||
.unwrap_or_else(|| PathBuf::from_str(&file.name).unwrap()),
|
||||
},
|
||||
);
|
||||
state.save();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut State) {
|
||||
fn draw(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins) {
|
||||
let mut output = plugins.egui(|ctx| {
|
||||
egui::SidePanel::left("side_panel").show(ctx, |ui| {
|
||||
ui.collapsing("Logs", |ui| {
|
||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||
let mut to_swap = None;
|
||||
let mut to_delete = None;
|
||||
let history_len = state.log_history.len();
|
||||
for (i, log) in state.log_history.iter().enumerate() {
|
||||
let path_text = log.path.to_string_lossy().to_string();
|
||||
let label = ui
|
||||
.add(Label::new(&log.name).sense(Sense::click()))
|
||||
.on_hover_text(&path_text);
|
||||
label.context_menu(|ui| {
|
||||
if ui.button("Open in Notepad").clicked() {
|
||||
_ = Command::new("notepad.exe").arg(&path_text).spawn();
|
||||
ui.close_menu();
|
||||
}
|
||||
if ui.button("Remove").clicked() {
|
||||
to_delete = Some(i);
|
||||
ui.close_menu();
|
||||
}
|
||||
});
|
||||
if label.clicked() {
|
||||
_ = Command::new("C:\\tools\\fast-log-viewer\\fast_log_viewer.exe")
|
||||
.arg(path_text)
|
||||
.spawn();
|
||||
to_swap = Some(i);
|
||||
}
|
||||
if i < history_len - 1 {
|
||||
ui.separator();
|
||||
}
|
||||
}
|
||||
if let Some(i) = to_swap {
|
||||
if let Some(value) = state.log_history.swap_remove_index(i) {
|
||||
state.log_history.shift_insert(0, value);
|
||||
}
|
||||
state.save();
|
||||
}
|
||||
if let Some(i) = to_delete {
|
||||
_ = state.log_history.shift_remove_index(i);
|
||||
state.save();
|
||||
}
|
||||
})
|
||||
})
|
||||
ui.heading("Egui Plugin Example");
|
||||
|
||||
ui.separator();
|
||||
if ui.button("Quit").clicked() {
|
||||
app.exit();
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
ui.label("Welcome to a basic example of how to use Egui with notan.");
|
||||
|
||||
ui.separator();
|
||||
ui.label("Check the source code to learn more about how it works");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -186,27 +64,33 @@ fn draw(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins, state: &mut St
|
|||
}
|
||||
|
||||
fn init(_gfx: &mut Graphics) -> State {
|
||||
let data = known_folders::get_known_folder_path(known_folders::KnownFolder::LocalAppData)
|
||||
.unwrap()
|
||||
.join("workspace")
|
||||
.join("data.rsn");
|
||||
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/icon.png");
|
||||
|
||||
let mut state = None;
|
||||
if data.exists() {
|
||||
match std::fs::read_to_string(data) {
|
||||
Ok(data) => {
|
||||
state = Some(rsn::from_str(&data).unwrap());
|
||||
}
|
||||
Err(err) => {
|
||||
warn!("Couldn't read data file: {}", err);
|
||||
}
|
||||
}
|
||||
let tray_menu = Menu::new();
|
||||
|
||||
let test = MenuItem::new("Test", true, None);
|
||||
let quit_i = MenuItem::new("Quit", true, None);
|
||||
tray_menu
|
||||
.append_items(&[&test, &PredefinedMenuItem::separator(), &quit_i])
|
||||
.unwrap();
|
||||
let icon = load_icon(std::path::Path::new(path));
|
||||
|
||||
let tray_icon = Some(
|
||||
TrayIconBuilder::new()
|
||||
.with_menu(Box::new(tray_menu.clone()))
|
||||
.with_tooltip("Workspace")
|
||||
.with_icon(icon)
|
||||
.build()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let menu_channel = MenuEvent::receiver().clone();
|
||||
|
||||
State {
|
||||
menu_channel,
|
||||
tray_icon,
|
||||
quit_i,
|
||||
}
|
||||
|
||||
state.unwrap_or_else(|| State {
|
||||
tray_data: TrayData::default(),
|
||||
log_history: IndexSet::new(),
|
||||
})
|
||||
}
|
||||
|
||||
fn load_icon(path: &std::path::Path) -> tray_icon::Icon {
|
||||
|
|
|
|||
Loading…
Reference in New Issue