mirror of
https://github.com/hinto-janai/gupax.git
synced 2024-11-16 17:27:37 +00:00
Merge branch 'egui'
This commit is contained in:
commit
3b7181e9c0
10 changed files with 551 additions and 570 deletions
954
Cargo.lock
generated
954
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
11
Cargo.toml
11
Cargo.toml
|
@ -33,10 +33,12 @@ benri = "0.1.12"
|
|||
bytes = "1.4.0"
|
||||
dirs = "5.0.1"
|
||||
#--------------------------------------------------------------------------------
|
||||
egui = "0.19.0"
|
||||
egui_extras = { version = "0.19.0", features = ["image"] }
|
||||
egui = "0.24.1"
|
||||
egui_extras = { version = "0.24.1", features = ["image"] }
|
||||
## 2023-12-28: https://github.com/hinto-janai/gupax/issues/68
|
||||
eframe = { version = "0.24.1", default-features = false, features = ["glow"] }
|
||||
|
||||
## Update 2023-Feb-06: The below gets fixed by using the [wgpu] backend instead of [glow]
|
||||
## 2023-02-06: The below gets fixed by using the [wgpu] backend instead of [glow]
|
||||
## It also fixes crashes on CPU-based graphics. Only used for Windows.
|
||||
## Using [wgpu] actually crashes macOS (fixed in 0.20.x though).
|
||||
|
||||
|
@ -79,8 +81,6 @@ strip-ansi-escapes = "0.2.0"
|
|||
tar = "0.4.38"
|
||||
flate2 = "1.0"
|
||||
sudo = "0.6.0"
|
||||
## [glow] backend for macOS/Linux.
|
||||
eframe = { version = "0.19.0", default-features = false, features = ["glow"] }
|
||||
|
||||
# macOS
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
|
@ -105,7 +105,6 @@ tls-api-native-tls = "0.9.0"
|
|||
[target.'cfg(windows)'.dependencies]
|
||||
zip = "0.6.6"
|
||||
is_elevated = "0.1.2"
|
||||
eframe = { version = "0.19.0", default-features = false, features = ["glow"] }
|
||||
|
||||
# For Windows build (icon)
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
|
|
2
external/egui
vendored
2
external/egui
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 62b4d427c01201898914594a9d00d1576bc23432
|
||||
Subproject commit 9cf535bd50b2602b0bce45c718d164bae2b4ed77
|
|
@ -425,6 +425,8 @@ pub static VISUALS: Lazy<Visuals> = Lazy::new(|| {
|
|||
stroke: Stroke::new(1.0, Color32::from_gray(255)),
|
||||
};
|
||||
|
||||
// Based off default dark() mode.
|
||||
// https://docs.rs/egui/0.24.1/src/egui/style.rs.html#1210
|
||||
let widgets = Widgets {
|
||||
noninteractive: WidgetVisuals {
|
||||
bg_fill: BG,
|
||||
|
@ -432,6 +434,7 @@ pub static VISUALS: Lazy<Visuals> = Lazy::new(|| {
|
|||
fg_stroke: Stroke::new(1.0, Color32::from_gray(140)), // normal text color
|
||||
rounding: Rounding::same(10.0),
|
||||
expansion: 0.0,
|
||||
weak_bg_fill: BG,
|
||||
},
|
||||
inactive: WidgetVisuals {
|
||||
bg_fill: Color32::from_gray(50),
|
||||
|
@ -439,6 +442,7 @@ pub static VISUALS: Lazy<Visuals> = Lazy::new(|| {
|
|||
fg_stroke: Stroke::new(1.0, Color32::from_gray(180)), // button text
|
||||
rounding: Rounding::same(10.0),
|
||||
expansion: 0.0,
|
||||
weak_bg_fill: Color32::from_gray(50),
|
||||
},
|
||||
hovered: WidgetVisuals {
|
||||
bg_fill: Color32::from_gray(80),
|
||||
|
@ -446,6 +450,7 @@ pub static VISUALS: Lazy<Visuals> = Lazy::new(|| {
|
|||
fg_stroke: Stroke::new(1.5, Color32::from_gray(240)),
|
||||
rounding: Rounding::same(10.0),
|
||||
expansion: 1.0,
|
||||
weak_bg_fill: Color32::from_gray(80),
|
||||
},
|
||||
active: WidgetVisuals {
|
||||
bg_fill: Color32::from_gray(55),
|
||||
|
@ -453,6 +458,7 @@ pub static VISUALS: Lazy<Visuals> = Lazy::new(|| {
|
|||
fg_stroke: Stroke::new(2.0, Color32::WHITE),
|
||||
rounding: Rounding::same(10.0),
|
||||
expansion: 1.0,
|
||||
weak_bg_fill: Color32::from_gray(120),
|
||||
},
|
||||
open: WidgetVisuals {
|
||||
bg_fill: Color32::from_gray(27),
|
||||
|
@ -460,29 +466,24 @@ pub static VISUALS: Lazy<Visuals> = Lazy::new(|| {
|
|||
fg_stroke: Stroke::new(1.0, Color32::from_gray(210)),
|
||||
rounding: Rounding::same(10.0),
|
||||
expansion: 0.0,
|
||||
weak_bg_fill: Color32::from_gray(120),
|
||||
},
|
||||
};
|
||||
|
||||
// https://docs.rs/egui/0.24.1/src/egui/style.rs.html#1113
|
||||
Visuals {
|
||||
dark_mode: true,
|
||||
override_text_color: None,
|
||||
widgets,
|
||||
selection,
|
||||
hyperlink_color: Color32::from_rgb(90, 170, 255),
|
||||
faint_bg_color: Color32::from_additive_luminance(5), // visible, but barely so
|
||||
extreme_bg_color: Color32::from_gray(10), // e.g. TextEdit background
|
||||
code_bg_color: Color32::from_gray(64),
|
||||
warn_fg_color: Color32::from_rgb(255, 143, 0), // orange
|
||||
error_fg_color: Color32::from_rgb(255, 0, 0), // red
|
||||
window_rounding: Rounding::same(6.0),
|
||||
window_shadow: Shadow::big_dark(),
|
||||
popup_shadow: Shadow::small_dark(),
|
||||
resize_corner_size: 12.0,
|
||||
text_cursor_width: 2.0,
|
||||
text_cursor_preview: false,
|
||||
clip_rect_margin: 3.0, // should be at least half the size of the widest frame stroke + max WidgetVisuals::expansion
|
||||
button_frame: true,
|
||||
collapsing_header_frame: false,
|
||||
hyperlink_color: Color32::from_rgb(90, 170, 255),
|
||||
faint_bg_color: Color32::from_additive_luminance(5), // visible, but barely so
|
||||
extreme_bg_color: Color32::from_gray(10), // e.g. TextEdit background
|
||||
code_bg_color: Color32::from_gray(64),
|
||||
warn_fg_color: Color32::from_rgb(255, 143, 0), // orange
|
||||
error_fg_color: Color32::from_rgb(255, 0, 0), // red
|
||||
window_rounding: Rounding::same(6.0),
|
||||
window_shadow: Shadow::big_dark(),
|
||||
popup_shadow: Shadow::small_dark(),
|
||||
..Visuals::dark()
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -259,7 +259,8 @@ impl crate::disk::Gupax {
|
|||
ui.separator();
|
||||
if ui.add_sized([width, height], SelectableLabel::new(self.ratio == None, "No lock")).on_hover_text(GUPAX_NO_LOCK).clicked() { self.ratio = None; }
|
||||
if ui.add_sized([width, height], Button::new("Set")).on_hover_text(GUPAX_SET).clicked() {
|
||||
frame.set_window_size(Vec2::new(self.selected_width as f32, self.selected_height as f32));
|
||||
let size = Vec2::new(self.selected_width as f32, self.selected_height as f32);
|
||||
ui.ctx().send_viewport_cmd(egui::viewport::ViewportCommand::InnerSize(size));
|
||||
}
|
||||
})});
|
||||
}
|
||||
|
|
94
src/main.rs
94
src/main.rs
|
@ -33,7 +33,7 @@ compile_error!("gupax is only built for windows/macos/linux");
|
|||
// egui/eframe
|
||||
use egui::{
|
||||
TextStyle::*,
|
||||
color::Color32,
|
||||
Color32,
|
||||
FontFamily::Proportional,
|
||||
TextStyle,Spinner,
|
||||
Layout,Align,
|
||||
|
@ -174,8 +174,7 @@ pub struct App {
|
|||
}
|
||||
|
||||
impl App {
|
||||
fn cc(cc: &eframe::CreationContext<'_>, app: Self) -> Self {
|
||||
let resolution = cc.integration_info.window_info.size;
|
||||
fn cc(cc: &eframe::CreationContext<'_>, resolution: Vec2, app: Self) -> Self {
|
||||
init_text_styles(&cc.egui_ctx, resolution[0], crate::free::clamp_scale(app.state.gupax.selected_scale));
|
||||
cc.egui_ctx.set_visuals(VISUALS.clone());
|
||||
Self {
|
||||
|
@ -812,7 +811,7 @@ impl KeyPressed {
|
|||
//---------------------------------------------------------------------------------------------------- Init functions
|
||||
#[inline(always)]
|
||||
fn init_text_styles(ctx: &egui::Context, width: f32, pixels_per_point: f32) {
|
||||
let scale = width / 30.0;
|
||||
let scale = width / 35.5;
|
||||
let mut style = (*ctx.style()).clone();
|
||||
style.text_styles = [
|
||||
(Small, FontId::new(scale/3.0, egui::FontFamily::Monospace)),
|
||||
|
@ -828,7 +827,10 @@ fn init_text_styles(ctx: &egui::Context, width: f32, pixels_per_point: f32) {
|
|||
style.spacing.icon_width_inner = width / 35.0;
|
||||
style.spacing.icon_width = width / 25.0;
|
||||
style.spacing.icon_spacing = 20.0;
|
||||
style.spacing.scroll_bar_width = width / 150.0;
|
||||
style.spacing.scroll = egui::style::ScrollStyle {
|
||||
bar_width: width / 150.0,
|
||||
..egui::style::ScrollStyle::solid()
|
||||
};
|
||||
ctx.set_style(style);
|
||||
// Make sure scale f32 is a regular number.
|
||||
let pixels_per_point = crate::free::clamp_scale(pixels_per_point);
|
||||
|
@ -875,18 +877,18 @@ fn init_logger(now: Instant) {
|
|||
#[inline(always)]
|
||||
fn init_options(initial_window_size: Option<Vec2>) -> NativeOptions {
|
||||
let mut options = eframe::NativeOptions::default();
|
||||
options.min_window_size = Some(Vec2::new(APP_MIN_WIDTH, APP_MIN_HEIGHT));
|
||||
options.max_window_size = Some(Vec2::new(APP_MAX_WIDTH, APP_MAX_HEIGHT));
|
||||
options.initial_window_size = initial_window_size;
|
||||
options.viewport.min_inner_size = Some(Vec2::new(APP_MIN_WIDTH, APP_MIN_HEIGHT));
|
||||
options.viewport.max_inner_size = Some(Vec2::new(APP_MAX_WIDTH, APP_MAX_HEIGHT));
|
||||
options.viewport.inner_size = initial_window_size;
|
||||
options.follow_system_theme = false;
|
||||
options.default_theme = eframe::Theme::Dark;
|
||||
let icon = image::load_from_memory(BYTES_ICON).expect("Failed to read icon bytes").to_rgba8();
|
||||
let (icon_width, icon_height) = icon.dimensions();
|
||||
options.icon_data = Some(eframe::IconData {
|
||||
options.viewport.icon = Some(Arc::new(egui::viewport::IconData {
|
||||
rgba: icon.into_raw(),
|
||||
width: icon_width,
|
||||
height: icon_height,
|
||||
});
|
||||
}));
|
||||
info!("init_options() ... OK");
|
||||
options
|
||||
}
|
||||
|
@ -1172,42 +1174,55 @@ fn main() {
|
|||
Err(e) => warn!("Could not cleanup [gupax_tmp] folders: {}", e),
|
||||
}
|
||||
|
||||
let resolution = Vec2::new(selected_width, selected_height);
|
||||
|
||||
// Run Gupax.
|
||||
info!("/*************************************/ Init ... OK /*************************************/");
|
||||
eframe::run_native(&app.name_version.clone(), options, Box::new(|cc| Box::new(App::cc(cc, app))),);
|
||||
eframe::run_native(&app.name_version.clone(), options, Box::new(move |cc| Box::new(App::cc(cc, resolution, app))),);
|
||||
}
|
||||
|
||||
impl eframe::App for App {
|
||||
#[inline(always)]
|
||||
fn on_close_event(&mut self) -> bool {
|
||||
if self.state.gupax.ask_before_quit {
|
||||
// If we're already on the [ask_before_quit] screen and
|
||||
// the user tried to exit again, exit.
|
||||
if self.error_state.quit_twice {
|
||||
if self.state.gupax.save_before_quit { self.save_before_quit(); }
|
||||
return true
|
||||
}
|
||||
// Else, set the error
|
||||
self.error_state.set("", ErrorFerris::Oops, ErrorButtons::StayQuit);
|
||||
self.error_state.quit_twice = true;
|
||||
false
|
||||
// Else, just quit.
|
||||
} else {
|
||||
if self.state.gupax.save_before_quit { self.save_before_quit(); }
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
// *-------*
|
||||
// | DEBUG |
|
||||
// *-------*
|
||||
debug!("App | ----------- Start of [update()] -----------");
|
||||
|
||||
// If closing.
|
||||
// Used to be `eframe::App::on_close_event(&mut self) -> bool`.
|
||||
let close_signal = ctx.input(|input| {
|
||||
use egui::viewport::ViewportCommand;
|
||||
|
||||
if !input.viewport().close_requested() {
|
||||
return None;
|
||||
}
|
||||
if self.state.gupax.ask_before_quit {
|
||||
// If we're already on the [ask_before_quit] screen and
|
||||
// the user tried to exit again, exit.
|
||||
if self.error_state.quit_twice {
|
||||
if self.state.gupax.save_before_quit { self.save_before_quit(); }
|
||||
return Some(ViewportCommand::Close);
|
||||
}
|
||||
// Else, set the error
|
||||
self.error_state.set("", ErrorFerris::Oops, ErrorButtons::StayQuit);
|
||||
self.error_state.quit_twice = true;
|
||||
Some(ViewportCommand::CancelClose)
|
||||
// Else, just quit.
|
||||
} else {
|
||||
if self.state.gupax.save_before_quit { self.save_before_quit(); }
|
||||
Some(ViewportCommand::Close)
|
||||
}
|
||||
});
|
||||
// This will either:
|
||||
// 1. Cancel a close signal
|
||||
// 2. Close the program
|
||||
if let Some(cmd) = close_signal {
|
||||
ctx.send_viewport_cmd(cmd);
|
||||
}
|
||||
|
||||
// If [F11] was pressed, reverse [fullscreen] bool
|
||||
let mut input = ctx.input_mut();
|
||||
let key: KeyPressed = {
|
||||
let key: KeyPressed = ctx.input_mut(|input| {
|
||||
if input.consume_key(Modifiers::NONE, Key::F11) {
|
||||
KeyPressed::F11
|
||||
} else if input.consume_key(Modifiers::NONE, Key::Z) {
|
||||
|
@ -1233,16 +1248,17 @@ impl eframe::App for App {
|
|||
} else {
|
||||
KeyPressed::None
|
||||
}
|
||||
};
|
||||
drop(input);
|
||||
});
|
||||
|
||||
// Check if egui wants keyboard input.
|
||||
// This prevents keyboard shortcuts from clobbering TextEdits.
|
||||
// (Typing S in text would always [Save] instead)
|
||||
let wants_input = ctx.wants_keyboard_input();
|
||||
|
||||
if key.is_f11() {
|
||||
let info = frame.info();
|
||||
frame.set_fullscreen(!info.window_info.fullscreen);
|
||||
if ctx.input(|i| i.viewport().maximized == Some(true)) {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Fullscreen(true));
|
||||
}
|
||||
// Change Tabs LEFT
|
||||
} else if key.is_z() && !wants_input {
|
||||
match self.tab {
|
||||
|
@ -1524,7 +1540,7 @@ impl eframe::App for App {
|
|||
ui.horizontal(|ui| {
|
||||
let response = ui.add_sized([sudo_width*8.0, height], TextEdit::hint_text(TextEdit::singleline(&mut sudo.pass).password(hide), PASSWORD_TEXT));
|
||||
let box_width = (ui.available_width()/2.0)-5.0;
|
||||
if (response.lost_focus() && ui.input().key_pressed(Key::Enter)) ||
|
||||
if (response.lost_focus() && ui.input(|i| i.key_pressed(Key::Enter))) ||
|
||||
ui.add_sized([box_width, height], Button::new("Enter")).on_hover_text(PASSWORD_ENTER).clicked() {
|
||||
response.request_focus();
|
||||
if !sudo.testing {
|
||||
|
|
|
@ -64,7 +64,7 @@ impl crate::disk::P2pool {
|
|||
ui.separator();
|
||||
let response = ui.add_sized([width, text_edit], TextEdit::hint_text(TextEdit::singleline(buffer), r#"Type a command (e.g "help" or "status") and press Enter"#)).on_hover_text(P2POOL_INPUT);
|
||||
// If the user pressed enter, dump buffer contents into the process STDIN
|
||||
if response.lost_focus() && ui.input().key_pressed(egui::Key::Enter) {
|
||||
if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
|
||||
response.request_focus(); // Get focus back
|
||||
let buffer = std::mem::take(buffer); // Take buffer
|
||||
let mut process = lock!(process); // Lock
|
||||
|
@ -151,7 +151,7 @@ impl crate::disk::P2pool {
|
|||
debug!("P2Pool Tab | Rendering [ComboBox] of Remote Nodes");
|
||||
let ip_location = crate::node::format_ip_location(&self.node, false);
|
||||
let text = RichText::new(format!(" ⏺ {}ms | {}", ms, ip_location)).color(color);
|
||||
ComboBox::from_id_source("remote_nodes").selected_text(text).show_ui(ui, |ui| {
|
||||
ComboBox::from_id_source("remote_nodes").selected_text(text).width(width).show_ui(ui, |ui| {
|
||||
for data in lock!(ping).nodes.iter() {
|
||||
let ms = crate::node::format_ms(data.ms);
|
||||
let ip_location = crate::node::format_ip_location(data.ip, true);
|
||||
|
@ -338,7 +338,7 @@ impl crate::disk::P2pool {
|
|||
// [Ping List]
|
||||
debug!("P2Pool Tab | Rendering [Node List]");
|
||||
let text = RichText::new(format!("{}. {}", self.selected_index+1, self.selected_name));
|
||||
ComboBox::from_id_source("manual_nodes").selected_text(text).show_ui(ui, |ui| {
|
||||
ComboBox::from_id_source("manual_nodes").selected_text(text).width(width).show_ui(ui, |ui| {
|
||||
let mut n = 0;
|
||||
for (name, node) in node_vec.iter() {
|
||||
let text = RichText::new(format!("{}. {}\n IP: {}\n RPC: {}\n ZMQ: {}", n+1, name, node.ip, node.rpc, node.zmq));
|
||||
|
|
|
@ -327,7 +327,12 @@ pub fn show(&mut self, sys: &Arc<Mutex<Sys>>, p2pool_api: &Arc<Mutex<PubP2poolAp
|
|||
ui.add_sized([width, text], Hyperlink::from_label_and_url("Other CPUs", "https://xmrig.com/benchmark")).on_hover_text(STATUS_SUBMENU_OTHER_CPUS);
|
||||
});
|
||||
|
||||
egui::ScrollArea::both().always_show_scroll(true).max_width(width).max_height(height).auto_shrink([false; 2]).show_viewport(ui, |ui, _| {
|
||||
egui::ScrollArea::both()
|
||||
.scroll_bar_visibility(egui::containers::scroll_area::ScrollBarVisibility::AlwaysVisible)
|
||||
.max_width(width)
|
||||
.max_height(height)
|
||||
.auto_shrink([false; 2])
|
||||
.show_viewport(ui, |ui, _| {
|
||||
let width = width / 20.0;
|
||||
let (cpu, bar, high, average, low, rank, bench) = (
|
||||
width*10.0,
|
||||
|
|
|
@ -65,6 +65,10 @@ impl AtomicUnit {
|
|||
self.0
|
||||
}
|
||||
|
||||
#[allow(clippy::inherent_to_string_shadow_display)]
|
||||
// This is terrible but it formats it in a different way
|
||||
// than `Display`, but for backwards compat, changing it
|
||||
// requires touching other code, so...
|
||||
pub fn to_string(self) -> String {
|
||||
self.0.to_string()
|
||||
}
|
||||
|
@ -400,6 +404,7 @@ r#"2022-09-08 18:42:55.4636 | 0.001000000000 XMR | Block 2,654,321
|
|||
]);
|
||||
println!("OG: {:#?}", payout_ord);
|
||||
|
||||
#[allow(clippy::never_loop)]
|
||||
for (_, atomic_unit, _) in payout_ord.rev_iter() {
|
||||
if atomic_unit.to_u64() == 3000000000 {
|
||||
break
|
||||
|
|
|
@ -65,7 +65,7 @@ impl crate::disk::Xmrig {
|
|||
ui.separator();
|
||||
let response = ui.add_sized([width, text_edit], TextEdit::hint_text(TextEdit::singleline(buffer), r#"Commands: [h]ashrate, [p]ause, [r]esume, re[s]ults, [c]onnection"#)).on_hover_text(XMRIG_INPUT);
|
||||
// If the user pressed enter, dump buffer contents into the process STDIN
|
||||
if response.lost_focus() && ui.input().key_pressed(egui::Key::Enter) {
|
||||
if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
|
||||
response.request_focus(); // Get focus back
|
||||
let buffer = std::mem::take(buffer); // Take buffer
|
||||
let mut process = lock!(process); // Lock
|
||||
|
@ -228,7 +228,7 @@ impl crate::disk::Xmrig {
|
|||
// [Node List]
|
||||
debug!("XMRig Tab | Rendering [Node List] ComboBox");
|
||||
let text = RichText::new(format!("{}. {}", self.selected_index+1, self.selected_name));
|
||||
ComboBox::from_id_source("manual_pool").selected_text(text).show_ui(ui, |ui| {
|
||||
ComboBox::from_id_source("manual_pool").selected_text(text).width(width).show_ui(ui, |ui| {
|
||||
let mut n = 0;
|
||||
for (name, pool) in pool_vec.iter() {
|
||||
let text = format!("{}. {}\n IP: {}\n Port: {}\n Rig: {}", n+1, name, pool.ip, pool.port, pool.rig);
|
||||
|
|
Loading…
Reference in a new issue