mirror of
https://github.com/jwinterm/grim.git
synced 2026-10-22 15:58:32 +02:00
ui: setup buttons style, add server loading progress for node and metrics, optimize node status
This commit is contained in:
@@ -22,14 +22,12 @@ mod modal;
|
||||
pub use modal::*;
|
||||
|
||||
mod network;
|
||||
pub use network::Network;
|
||||
|
||||
mod network_node;
|
||||
mod network_settings;
|
||||
mod network_metrics;
|
||||
mod network_mining;
|
||||
pub use network::Network;
|
||||
|
||||
mod progress_loading;
|
||||
pub use progress_loading::ProgressLoading;
|
||||
|
||||
pub trait NetworkTab {
|
||||
fn name(&self) -> &String;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
use std::cmp::min;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use egui::{Align2, Color32, RichText, Rounding, Sense, Stroke, Vec2};
|
||||
use egui::{Align2, Color32, RichText, Rounding, Sense, Separator, Stroke, Vec2, Widget};
|
||||
use egui::epaint::RectShape;
|
||||
use egui::style::Margin;
|
||||
use egui_extras::{Size, StripBuilder};
|
||||
@@ -29,7 +29,6 @@ pub enum ModalId {
|
||||
}
|
||||
|
||||
/// Location for [`Modal`] at application UI.
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ModalLocation {
|
||||
/// To draw globally above side panel and screen.
|
||||
Global,
|
||||
@@ -204,7 +203,7 @@ impl Modal {
|
||||
rect,
|
||||
rounding,
|
||||
fill: COLOR_LIGHT,
|
||||
stroke: View::DEFAULT_STROKE,
|
||||
stroke: Stroke::NONE,
|
||||
};
|
||||
let bg_idx = ui.painter().add(bg_shape);
|
||||
|
||||
@@ -250,5 +249,11 @@ impl Modal {
|
||||
// Setup background shape to be painted behind title content.
|
||||
bg_shape.rect = title_resp.rect;
|
||||
ui.painter().set(bg_idx, bg_shape);
|
||||
|
||||
let (rect, _) = ui.allocate_exact_size(Vec2::new(ui.available_width(), 1.0),Sense::hover());
|
||||
let painter = ui.painter();
|
||||
painter.hline(rect.x_range(),
|
||||
painter.round_to_pixel(rect.center().y),
|
||||
View::DEFAULT_STROKE);
|
||||
}
|
||||
}
|
||||
+30
-12
@@ -20,8 +20,8 @@ use egui_extras::{Size, StripBuilder};
|
||||
use grin_chain::SyncStatus;
|
||||
use grin_core::global::ChainTypes;
|
||||
|
||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY_DARK, COLOR_YELLOW};
|
||||
use crate::gui::icons::{CARDHOLDER, DATABASE, DOTS_THREE_OUTLINE_VERTICAL, FACTORY, FADERS, GAUGE};
|
||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_GRAY_DARK, COLOR_YELLOW};
|
||||
use crate::gui::icons::{CARDHOLDER, DATABASE, DOTS_THREE_OUTLINE_VERTICAL, FACTORY, FADERS, GAUGE, PLUGS, POWER};
|
||||
use crate::gui::Navigator;
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{NetworkTab, View};
|
||||
@@ -71,7 +71,7 @@ impl Network {
|
||||
|
||||
egui::TopBottomPanel::bottom("network_tabs")
|
||||
.frame(egui::Frame {
|
||||
outer_margin: Margin::same(6.0),
|
||||
outer_margin: Margin::same(5.0),
|
||||
.. Default::default()
|
||||
})
|
||||
.resizable(false)
|
||||
@@ -93,26 +93,28 @@ impl Network {
|
||||
|
||||
fn draw_tabs(&mut self, ui: &mut egui::Ui) {
|
||||
ui.scope(|ui| {
|
||||
//Setup spacing between tabs
|
||||
ui.style_mut().spacing.item_spacing = egui::vec2(6.0, 0.0);
|
||||
// Setup spacing between tabs.
|
||||
ui.style_mut().spacing.item_spacing = egui::vec2(5.0, 0.0);
|
||||
// Setup vertical padding inside tab button.
|
||||
ui.style_mut().spacing.button_padding = egui::vec2(0.0, 3.0);
|
||||
|
||||
ui.columns(4, |columns| {
|
||||
columns[0].vertical_centered(|ui| {
|
||||
columns[0].vertical_centered_justified(|ui| {
|
||||
View::tab_button(ui, DATABASE, self.current_mode == Mode::Node, || {
|
||||
self.current_mode = Mode::Node;
|
||||
});
|
||||
});
|
||||
columns[1].vertical_centered(|ui| {
|
||||
columns[1].vertical_centered_justified(|ui| {
|
||||
View::tab_button(ui, GAUGE, self.current_mode == Mode::Metrics, || {
|
||||
self.current_mode = Mode::Metrics;
|
||||
});
|
||||
});
|
||||
columns[2].vertical_centered(|ui| {
|
||||
columns[2].vertical_centered_justified(|ui| {
|
||||
View::tab_button(ui, FACTORY, self.current_mode == Mode::Miner, || {
|
||||
self.current_mode = Mode::Miner;
|
||||
});
|
||||
});
|
||||
columns[3].vertical_centered(|ui| {
|
||||
columns[3].vertical_centered_justified(|ui| {
|
||||
View::tab_button(ui, FADERS, self.current_mode == Mode::Tuning, || {
|
||||
self.current_mode = Mode::Tuning;
|
||||
});
|
||||
@@ -200,9 +202,7 @@ impl Network {
|
||||
});
|
||||
strip.cell(|ui| {
|
||||
ui.centered_and_justified(|ui| {
|
||||
// Select sync status text
|
||||
let sync_status = Node::get_sync_status();
|
||||
let status_text = Node::get_sync_status_text(sync_status);
|
||||
|
||||
// Setup text color animation based on sync status
|
||||
let idle = match sync_status {
|
||||
@@ -219,7 +219,7 @@ impl Network {
|
||||
// Draw sync text
|
||||
let status_color_rgba = Rgba::from(COLOR_GRAY_DARK) * color_factor as f32;
|
||||
let status_color = Color32::from(status_color_rgba);
|
||||
View::ellipsize_text(ui, status_text, 15.0, status_color);
|
||||
View::ellipsize_text(ui, Node::get_sync_status_text(), 15.0, status_color);
|
||||
|
||||
// Repaint based on sync status
|
||||
if idle {
|
||||
@@ -231,5 +231,23 @@ impl Network {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
pub fn server_off_content(ui: &mut egui::Ui) {
|
||||
View::center_content(ui, [240.0, 214.0], |ui| {
|
||||
ui.label(RichText::new(PLUGS)
|
||||
.size(84.0)
|
||||
.color(Color32::from_gray(200))
|
||||
);
|
||||
ui.add_space(-16.0);
|
||||
ui.label(RichText::new(Node::get_sync_status_text())
|
||||
.size(19.0)
|
||||
.color(Color32::from_gray(150))
|
||||
);
|
||||
ui.add_space(12.0);
|
||||
View::button(ui, format!("{} {}", POWER, t!("network.enable")), COLOR_YELLOW, || {
|
||||
Node::start(ChainTypes::Mainnet);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,11 +15,12 @@
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use eframe::epaint::{Color32, Rounding, Stroke};
|
||||
use egui::{RichText, ScrollArea, Spinner, Widget};
|
||||
use grin_core::global::ChainTypes;
|
||||
use grin_servers::DiffBlock;
|
||||
|
||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_GRAY_LIGHT};
|
||||
use crate::gui::icons::{AT, COINS, CUBE_TRANSPARENT, HASH, HOURGLASS_LOW, HOURGLASS_MEDIUM, TIMER};
|
||||
use crate::gui::views::{NetworkTab, View};
|
||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_GRAY_LIGHT, COLOR_YELLOW};
|
||||
use crate::gui::icons::{AT, COINS, CUBE_TRANSPARENT, HASH, HOURGLASS_LOW, HOURGLASS_MEDIUM, PLUGS, POWER, TIMER};
|
||||
use crate::gui::views::{Network, NetworkTab, View};
|
||||
use crate::node::Node;
|
||||
|
||||
pub struct NetworkMetrics {
|
||||
@@ -45,11 +46,19 @@ impl NetworkTab for NetworkMetrics {
|
||||
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
let server_stats = Node::get_stats();
|
||||
// Show loading widget if server is not working or difficulty height is zero.
|
||||
if !server_stats.is_some() || server_stats.as_ref().unwrap().diff_stats.height == 0 {
|
||||
ui.centered_and_justified(|ui| {
|
||||
Spinner::new().size(42.0).color(COLOR_GRAY).ui(ui);
|
||||
});
|
||||
if server_stats.is_none() || server_stats.as_ref().unwrap().diff_stats.height == 0 {
|
||||
if !Node::is_running() {
|
||||
Network::server_off_content(ui);
|
||||
} else {
|
||||
View::center_content(ui, [280.0, 160.0], |ui| {
|
||||
Spinner::new().size(104.0).color(COLOR_YELLOW).ui(ui);
|
||||
ui.add_space(18.0);
|
||||
ui.label(RichText::new(t!("network_metrics.loading"))
|
||||
.size(16.0)
|
||||
.color(Color32::from_gray(150))
|
||||
);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,3 +11,28 @@
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use egui::Ui;
|
||||
use crate::gui::views::NetworkTab;
|
||||
|
||||
pub struct NetworkMining {
|
||||
title: String
|
||||
}
|
||||
|
||||
impl Default for NetworkMining {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
title: t!("network.mining").to_uppercase(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkTab for NetworkMining {
|
||||
fn name(&self) -> &String {
|
||||
&self.title
|
||||
}
|
||||
|
||||
fn ui(&mut self, ui: &mut Ui) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,13 @@
|
||||
|
||||
use eframe::epaint::Stroke;
|
||||
use egui::{Color32, RichText, Rounding, ScrollArea, Spinner, Widget};
|
||||
use egui_extras::{Size, StripBuilder};
|
||||
use grin_core::global::ChainTypes;
|
||||
use grin_servers::PeerStats;
|
||||
|
||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_GRAY_LIGHT};
|
||||
use crate::gui::icons::{AT, CUBE, DEVICES, FLOW_ARROW, HANDSHAKE, PACKAGE, PLUGS_CONNECTED, SHARE_NETWORK};
|
||||
use crate::gui::views::{NetworkTab, View};
|
||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_GRAY_LIGHT, COLOR_YELLOW};
|
||||
use crate::gui::icons::{AT, CUBE, DEVICES, FLOW_ARROW, HANDSHAKE, PACKAGE, PLUGS, PLUGS_CONNECTED, POWER, SHARE_NETWORK};
|
||||
use crate::gui::views::{Network, NetworkTab, View};
|
||||
use crate::node::Node;
|
||||
|
||||
pub struct NetworkNode {
|
||||
@@ -41,9 +43,13 @@ impl NetworkTab for NetworkNode {
|
||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
let server_stats = Node::get_stats();
|
||||
if !server_stats.is_some() {
|
||||
ui.centered_and_justified(|ui| {
|
||||
Spinner::new().size(42.0).color(COLOR_GRAY).ui(ui);
|
||||
});
|
||||
if !Node::is_running() {
|
||||
Network::server_off_content(ui);
|
||||
} else {
|
||||
ui.centered_and_justified(|ui| {
|
||||
Spinner::new().size(104.0).color(COLOR_YELLOW).ui(ui);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2023 The Grim Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use egui::{Response, RichText, Spinner, Ui, Widget};
|
||||
|
||||
use crate::gui::colors::COLOR_DARK;
|
||||
|
||||
pub struct ProgressLoading {
|
||||
text: String
|
||||
}
|
||||
|
||||
impl ProgressLoading {
|
||||
pub fn new(text: String) -> Self {
|
||||
Self {
|
||||
text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for ProgressLoading {
|
||||
fn ui(self, ui: &mut Ui) -> Response {
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
ui.add_space(10.0);
|
||||
Spinner::new().size(36.0).color(COLOR_DARK).ui(ui);
|
||||
ui.add_space(10.0);
|
||||
ui.label(RichText::new(self.text).size(18.0).color(COLOR_DARK));
|
||||
}).response
|
||||
}
|
||||
}
|
||||
+20
-10
@@ -14,10 +14,11 @@
|
||||
|
||||
use egui::epaint::{Color32, FontId, Rounding, Stroke};
|
||||
use egui::text::{LayoutJob, TextFormat};
|
||||
use egui::{Button, PointerState, Response, RichText, Sense, Widget};
|
||||
use egui::{Button, PointerState, Response, RichText, Sense, Vec2, Widget};
|
||||
use egui::epaint::text::TextWrapping;
|
||||
use egui_extras::{Size, StripBuilder};
|
||||
|
||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_LIGHT, COLOR_GRAY_LIGHT, COLOR_GRAY_DARK};
|
||||
use crate::gui::colors::{COLOR_DARK, COLOR_GRAY, COLOR_LIGHT, COLOR_GRAY_LIGHT, COLOR_GRAY_DARK, COLOR_YELLOW};
|
||||
|
||||
pub struct View;
|
||||
|
||||
@@ -103,7 +104,6 @@ impl View {
|
||||
false => { Color32::WHITE }
|
||||
};
|
||||
let br = Button::new(wt)
|
||||
.min_size(ui.available_size_before_wrap())
|
||||
.stroke(stroke)
|
||||
.fill(color)
|
||||
.ui(ui).interact(Sense::click_and_drag());
|
||||
@@ -111,16 +111,12 @@ impl View {
|
||||
Self::on_button_click(ui, br, action);
|
||||
}
|
||||
|
||||
/// Modal button with white background fill color, contains text.
|
||||
pub fn modal_button(ui: &mut egui::Ui, text: String, action: impl FnOnce()) {
|
||||
let mut size = ui.available_size_before_wrap();
|
||||
size.y = 36.0;
|
||||
|
||||
/// Draw [`Button`] with specified background fill color.
|
||||
pub fn button(ui: &mut egui::Ui, text: String, fill_color: Color32, action: impl FnOnce()) {
|
||||
let wt = RichText::new(text.to_uppercase()).size(18.0).color(COLOR_GRAY_DARK);
|
||||
let br = Button::new(wt)
|
||||
.stroke(Self::DEFAULT_STROKE)
|
||||
.min_size(size)
|
||||
.fill(Color32::WHITE)
|
||||
.fill(fill_color)
|
||||
.ui(ui).interact(Sense::click_and_drag());
|
||||
|
||||
Self::on_button_click(ui, br, action);
|
||||
@@ -169,4 +165,18 @@ impl View {
|
||||
ui.label(RichText::new(label).color(COLOR_GRAY).size(15.0));
|
||||
});
|
||||
}
|
||||
|
||||
/// Draw content in the center of current layout with specified width and height.
|
||||
pub fn center_content(ui: &mut egui::Ui, w_h: [f32; 2], content: impl FnOnce(&mut egui::Ui)) {
|
||||
ui.vertical_centered(|ui| {
|
||||
let mut rect = ui.available_rect_before_wrap();
|
||||
let side_margin = (ui.available_width() - w_h[0]) / 2.0;
|
||||
rect.min += egui::emath::vec2(side_margin, ui.available_height() / 2.0 - w_h[1] / 2.0);
|
||||
rect.max -= egui::emath::vec2(side_margin, 0.0);
|
||||
// rect.set_width(w_h[0]);
|
||||
ui.allocate_ui_at_rect(rect, |ui| {
|
||||
(content)(ui);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user