Merge branch 'egui'

This commit is contained in:
hinto.janai 2023-12-28 16:03:00 -05:00
commit 3b7181e9c0
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
10 changed files with 551 additions and 570 deletions

954
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -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

@ -1 +1 @@
Subproject commit 62b4d427c01201898914594a9d00d1576bc23432
Subproject commit 9cf535bd50b2602b0bce45c718d164bae2b4ed77

View file

@ -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()
}
});

View file

@ -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));
}
})});
}

View file

@ -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 {

View file

@ -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));

View file

@ -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,

View file

@ -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

View file

@ -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);