diff --git a/locales/en.yml b/locales/en.yml index 06210b7..38f54cc 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -3,7 +3,7 @@ screen_accounts: network: self: Network node: Integrated node - metrics: Network metrics + metrics: Chain metrics mining: Mining settings: Node settings enable_node: Enable node @@ -46,7 +46,7 @@ network_node: size: Size (GB) peers: Peers network_metrics: - loading: Metrics will be available after the synchronization + loading: Chain metrics will be available after the synchronization emission: Emission inflation: Inflation supply: Supply @@ -57,7 +57,6 @@ network_mining: loading: Mining will be available after the synchronization enable_server: Enable server disabled_server: 'Enable stratum server at %{address} or change settings by selecting %{settings} at the bottom of the screen.' - starting: Stratum server is starting info: 'Mining server is enabled, you can change settings by selecting %{settings} at the bottom of the screen. Data is updating when devices are connected.' address: IP Address wallet: Wallet Address @@ -65,9 +64,11 @@ network_mining: miners: Miners devices: Devices blocks_found: Blocks found - hashrate: Hashrate + hashrate: 'Hashrate (C%{bits})' + connected: Connected + disconnected: Disconnected modal: cancel: Cancel modal_exit: - description: Are you sure you want to quit the app? + description: Are you sure you want to quit the application? exit: Exit \ No newline at end of file diff --git a/locales/ru.yml b/locales/ru.yml index 1881d51..9b3dc0f 100644 --- a/locales/ru.yml +++ b/locales/ru.yml @@ -3,7 +3,7 @@ screen_accounts: network: self: Сеть node: Встроенный узел - metrics: Показатели сети + metrics: Показатели цепи mining: Майнинг settings: Настройки узла enable_node: Включить узел @@ -46,7 +46,7 @@ network_node: size: Размер (ГБ) peers: Пиры network_metrics: - loading: Метрики будут доступны после синхронизации + loading: Показатели цепи будут доступны после синхронизации emission: Эмиссия inflation: Инфляция supply: Предложение @@ -57,7 +57,6 @@ network_mining: loading: Майнинг будет доступен после синхронизации enable_server: Включить сервер disabled_server: 'Включите stratum-сервер по адресу %{address} или измените настройки, выбрав %{settings} внизу экрана.' - starting: Stratum-сервер запускается info: 'Сервер майнинга запущен, вы можете изменить настройки, выбрав %{settings} внизу экрана. Данные обновляются, когда устройства подключены.' address: IP Адрес wallet: Адрес кошелька @@ -65,7 +64,9 @@ network_mining: miners: Майнеры devices: Устройства found: Найдено - hashrate: Хешрэйт + hashrate: 'Хешрэйт (C%{bits})' + connected: Подключен + disconnected: Отключен modal: cancel: Отмена modal_exit: diff --git a/src/gui/colors.rs b/src/gui/colors.rs index 3b81ee6..7cd187e 100644 --- a/src/gui/colors.rs +++ b/src/gui/colors.rs @@ -23,6 +23,8 @@ impl Colors { pub const SEMI_TRANSPARENT: Color32 = Color32::from_black_alpha(100); pub const YELLOW: Color32 = Color32::from_rgb(254, 241, 2); pub const GOLD: Color32 = Color32::from_rgb(255, 215, 0); + pub const GREEN: Color32 = Color32::from_rgb(0, 0x64, 0); + pub const RED: Color32 = Color32::from_rgb(0x8B, 0, 0); pub const FILL: Color32 = Color32::from_gray(240); pub const TITLE: Color32 = Color32::from_gray(60); pub const TEXT: Color32 = Color32::from_gray(80); diff --git a/src/gui/views/network_metrics.rs b/src/gui/views/network_metrics.rs index 2bb6057..ec1272b 100644 --- a/src/gui/views/network_metrics.rs +++ b/src/gui/views/network_metrics.rs @@ -13,8 +13,7 @@ // limitations under the License. use chrono::{DateTime, NaiveDateTime, Utc}; -use eframe::epaint::{Color32, Rounding, Stroke}; -use egui::{RichText, ScrollArea}; +use egui::{RichText, Rounding, ScrollArea, Stroke}; use grin_servers::DiffBlock; use crate::gui::Colors; @@ -56,15 +55,11 @@ impl NetworkTab for NetworkMetrics { let stats = server_stats.as_ref().unwrap(); // Show emission info. - ui.vertical_centered_justified(|ui| { - View::sub_header(ui, format!("{} {}", COINS, t!("network_metrics.emission"))); - }); - ui.add_space(4.0); - - let supply = stats.header_stats.height as f64 * BLOCK_REWARD; - let rate = (YEARLY_SUPPLY * 100.0) / supply; - + View::sub_title(ui, format!("{} {}", COINS, t!("network_metrics.emission"))); ui.columns(3, |columns| { + let supply = stats.header_stats.height as f64 * BLOCK_REWARD; + let rate = (YEARLY_SUPPLY * 100.0) / supply; + columns[0].vertical_centered(|ui| { View::rounded_box(ui, format!("{}ツ", BLOCK_REWARD), @@ -87,14 +82,11 @@ impl NetworkTab for NetworkMetrics { ui.add_space(4.0); // Show difficulty adjustment window info - ui.vertical_centered_justified(|ui| { - let title = t!( + let difficulty_title = t!( "network_metrics.difficulty_window", "size" => stats.diff_stats.window_size ); - View::sub_header(ui, format!("{} {}", HOURGLASS_MEDIUM, title)); - }); - ui.add_space(4.0); + View::sub_title(ui, format!("{} {}", HOURGLASS_MEDIUM, difficulty_title)); ui.columns(3, |columns| { columns[0].vertical_centered(|ui| { View::rounded_box(ui, @@ -146,10 +138,10 @@ impl NetworkTab for NetworkMetrics { } } -const DIFF_BLOCK_UI_HEIGHT: f32 = 77.0; +const DIFF_BLOCK_UI_HEIGHT: f32 = 76.60; fn draw_diff_block(ui: &mut egui::Ui, db: &DiffBlock, rounding: [bool; 2]) { - // Add space before first item + // Add space before the first item. if rounding[0] { ui.add_space(4.0); } @@ -167,7 +159,7 @@ fn draw_diff_block(ui: &mut egui::Ui, db: &DiffBlock, rounding: [bool; 2]) { sw: if rounding[1] { 8.0 } else { 0.0 }, se: if rounding[1] { 8.0 } else { 0.0 }, }, - Color32::WHITE, + Colors::WHITE, Stroke { width: 1.0, color: Colors::ITEM_STROKE } ); @@ -179,7 +171,7 @@ fn draw_diff_block(ui: &mut egui::Ui, db: &DiffBlock, rounding: [bool; 2]) { .size(18.0)); ui.add_space(2.0); - // Draw block hash + // Draw block hash. ui.heading(RichText::new(db.block_hash.to_string()) .color(Colors::BLACK) .size(18.0)); @@ -189,9 +181,8 @@ fn draw_diff_block(ui: &mut egui::Ui, db: &DiffBlock, rounding: [bool; 2]) { ui.heading(RichText::new(CUBE_TRANSPARENT) .color(Colors::TITLE) .size(16.0)); - ui.add_space(4.0); - - // Draw block difficulty and height + ui.add_space(3.0); + // Draw block difficulty and height. ui.heading(RichText::new(db.difficulty.to_string()) .color(Colors::TITLE) .size(16.0)); @@ -207,23 +198,21 @@ fn draw_diff_block(ui: &mut egui::Ui, db: &DiffBlock, rounding: [bool; 2]) { ui.heading(RichText::new(TIMER) .color(Colors::GRAY) .size(16.0)); - ui.add_space(4.0); - - // Draw block time + ui.add_space(3.0); + // Draw block date. ui.heading(RichText::new(format!("{}s", db.duration)) .color(Colors::GRAY) .size(16.0)); - ui.add_space(2.0); + ui.add_space(4.0); + ui.heading(RichText::new(HOURGLASS_LOW).color(Colors::GRAY).size(16.0)); ui.add_space(2.0); - - let naive_datetime = NaiveDateTime::from_timestamp_opt(db.time as i64, 0); - if naive_datetime.is_some() { - let datetime: DateTime = DateTime::from_utc(naive_datetime.unwrap(), Utc); - ui.heading(RichText::new(datetime.to_string()) - .color(Colors::GRAY) - .size(16.0)); - } + // Draw block time. + let block_time = NaiveDateTime::from_timestamp_opt(db.time as i64, 0).unwrap(); + let block_datetime: DateTime = DateTime::from_utc(block_time, Utc); + ui.heading(RichText::new(block_datetime.to_string()) + .color(Colors::GRAY) + .size(16.0)); }); ui.add_space(2.0); }); diff --git a/src/gui/views/network_mining.rs b/src/gui/views/network_mining.rs index ff21391..6d804b0 100644 --- a/src/gui/views/network_mining.rs +++ b/src/gui/views/network_mining.rs @@ -12,11 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::RichText; +use chrono::{DateTime, NaiveDateTime, Utc}; +use egui::{RichText, Rounding, ScrollArea, Stroke}; use grin_chain::SyncStatus; +use grin_servers::WorkerStats; use crate::gui::Colors; -use crate::gui::icons::{COMPUTER_TOWER, CPU, FADERS, POLYGON}; +use crate::gui::icons::{BARBELL, CLOCK_AFTERNOON, COMPUTER_TOWER, CPU, CUBE, FADERS, FOLDER_DASHED, FOLDER_NOTCH_MINUS, FOLDER_NOTCH_PLUS, PLUGS, PLUGS_CONNECTED, POLYGON}; use crate::gui::views::{Network, NetworkTab, NetworkTabType, View}; use crate::node::Node; use crate::Settings; @@ -68,6 +70,18 @@ impl NetworkTab for NetworkMining { .color(Colors::INACTIVE_TEXT) ); + let mut addresses = Vec::new(); + for net_if in pnet::datalink::interfaces() { + for ip in net_if.ips { + if ip.is_ipv4() { + addresses.push(ip); + } + } + } + if addresses.len() != 0 { + + } + ui.add_space(10.0); View::button(ui, t!("network_mining.enable_server"), Colors::GOLD, || { @@ -76,7 +90,7 @@ impl NetworkTab for NetworkMining { ui.add_space(2.0); - // Check if stratum server is enabled at config + // Check if stratum server is enabled at config. let stratum_enabled = Settings::node_config_to_read() .members.clone() .server.stratum_mining_config.unwrap() @@ -93,23 +107,14 @@ impl NetworkTab for NetworkMining { return; } else if Node::is_stratum_server_starting() { // Show loading spinner when mining server is starting. - View::center_content(ui, 162.0, |ui| { + ui.centered_and_justified(|ui| { View::big_loading_spinner(ui); - ui.add_space(18.0); - ui.label(RichText::new(t!("network_mining.starting")) - .size(16.0) - .color(Colors::INACTIVE_TEXT) - ); }); return; } // Show stratum mining server info. - ui.vertical_centered_justified(|ui| { - View::sub_header(ui, format!("{} {}", COMPUTER_TOWER, t!("network_mining.server"))); - }); - ui.add_space(4.0); - + View::sub_title(ui, format!("{} {}", COMPUTER_TOWER, t!("network_mining.server"))); ui.columns(2, |columns| { columns[0].vertical_centered(|ui| { View::rounded_box(ui, @@ -118,11 +123,12 @@ impl NetworkTab for NetworkMining { [true, false, true, false]); }); columns[1].vertical_centered(|ui| { - // Stratum mining wallet address. + //TODO: Stratum mining wallet listening address. Replace with local wallet name. let wallet_address = Settings::node_config_to_read() .members.clone() .server.stratum_mining_config.unwrap() - .wallet_listener_url; + .wallet_listener_url + .replace("http://", ""); View::rounded_box(ui, wallet_address, t!("network_mining.wallet"), @@ -132,11 +138,7 @@ impl NetworkTab for NetworkMining { ui.add_space(4.0); // Show network info. - ui.vertical_centered_justified(|ui| { - View::sub_header(ui, format!("{} {}", POLYGON, t!("network.self"))); - }); - ui.add_space(4.0); - + View::sub_title(ui, format!("{} {}", POLYGON, t!("network.self"))); ui.columns(3, |columns| { columns[0].vertical_centered(|ui| { let difficulty = if stratum_stats.network_difficulty > 0 { @@ -162,24 +164,20 @@ impl NetworkTab for NetworkMining { }); columns[2].vertical_centered(|ui| { let hashrate = if stratum_stats.network_hashrate > 0.0 { - stratum_stats.network_hashrate.to_string() + format!("{:.*}", 2, stratum_stats.network_hashrate) } else { "-".into() }; View::rounded_box(ui, hashrate, - t!("network_mining.hashrate"), + t!("network_mining.hashrate", "bits" => stratum_stats.edge_bits), [false, true, false, true]); }); }); ui.add_space(4.0); // Show mining info. - ui.vertical_centered_justified(|ui| { - View::sub_header(ui, format!("{} {}", CPU, t!("network_mining.miners"))); - }); - ui.add_space(4.0); - + View::sub_title(ui, format!("{} {}", CPU, t!("network_mining.miners"))); ui.columns(2, |columns| { columns[0].vertical_centered(|ui| { View::rounded_box(ui, @@ -197,9 +195,32 @@ impl NetworkTab for NetworkMining { }); ui.add_space(4.0); - // Show miners info. - if !stratum_stats.worker_stats.is_empty() { - //TODO: miners workers + // Show workers stats or info text when possible. + let workers_size = stratum_stats.worker_stats.len(); + if workers_size != 0 && stratum_stats.num_workers > 0 { + ScrollArea::vertical() + .auto_shrink([false; 2]) + .id_source("stratum_workers_scroll") + .show_rows( + ui, + WORKER_UI_HEIGHT, + workers_size, + |ui, row_range| { + for index in row_range { + let worker = stratum_stats.worker_stats.get(index).unwrap(); + let rounding = if workers_size == 1 { + [true, true] + } else if index == 0 { + [true, false] + } else if index == workers_size - 1 { + [false, true] + } else { + [false, false] + }; + draw_worker_stats(ui, worker, rounding) + } + }, + ); } else if ui.available_height() > 142.0 { View::center_content(ui, 142.0, |ui| { ui.label(RichText::new(t!("network_mining.info", "settings" => FADERS)) @@ -209,4 +230,124 @@ impl NetworkTab for NetworkMining { }); } } +} + +const WORKER_UI_HEIGHT: f32 = 77.0; + +fn draw_worker_stats(ui: &mut egui::Ui, ws: &WorkerStats, rounding: [bool; 2]) { + // Add space before the first item. + if rounding[0] { + ui.add_space(4.0); + } + + ui.horizontal(|ui| { + ui.add_space(6.0); + ui.vertical(|ui| { + let mut rect = ui.available_rect_before_wrap(); + rect.set_height(WORKER_UI_HEIGHT); + ui.painter().rect( + rect, + Rounding { + nw: if rounding[0] { 8.0 } else { 0.0 }, + ne: if rounding[0] { 8.0 } else { 0.0 }, + sw: if rounding[1] { 8.0 } else { 0.0 }, + se: if rounding[1] { 8.0 } else { 0.0 }, + }, + Colors::WHITE, + Stroke { width: 1.0, color: Colors::ITEM_STROKE } + ); + + ui.add_space(2.0); + ui.horizontal_top(|ui| { + let (status_text, status_icon) = match ws.is_connected { + true => { (t!("network_mining.connected"), PLUGS_CONNECTED) } + false => { (t!("network_mining.disconnected"), PLUGS) } + }; + ui.add_space(5.0); + ui.heading(RichText::new(status_icon) + .color(Colors::BLACK) + .size(18.0)); + ui.add_space(2.0); + + // Draw worker ID. + ui.heading(RichText::new(&ws.id) + .color(Colors::BLACK) + .size(18.0)); + ui.add_space(3.0); + + // Draw worker status. + ui.heading(RichText::new(status_text) + .color(Colors::BLACK) + .size(18.0)); + }); + ui.horizontal_top(|ui| { + ui.add_space(6.0); + ui.heading(RichText::new(BARBELL) + .color(Colors::TITLE) + .size(16.0)); + ui.add_space(4.0); + // Draw difficulty. + ui.heading(RichText::new(ws.pow_difficulty.to_string()) + .color(Colors::TITLE) + .size(16.0)); + ui.add_space(6.0); + + ui.heading(RichText::new(FOLDER_NOTCH_PLUS) + .color(Colors::GREEN) + .size(16.0)); + ui.add_space(3.0); + // Draw accepted shares. + ui.heading(RichText::new(ws.num_accepted.to_string()) + .color(Colors::GREEN) + .size(16.0)); + ui.add_space(6.0); + + ui.heading(RichText::new(FOLDER_NOTCH_MINUS) + .color(Colors::RED) + .size(16.0)); + ui.add_space(3.0); + // Draw rejected shares. + ui.heading(RichText::new(ws.num_rejected.to_string()) + .color(Colors::RED) + .size(16.0)); + ui.add_space(6.0); + + ui.heading(RichText::new(FOLDER_DASHED) + .color(Colors::GRAY) + .size(16.0)); + ui.add_space(3.0); + // Draw stale shares. + ui.heading(RichText::new(ws.num_stale.to_string()) + .color(Colors::GRAY) + .size(16.0)); + ui.add_space(6.0); + + ui.heading(RichText::new(CUBE) + .color(Colors::TITLE) + .size(16.0)); + ui.add_space(3.0); + // Draw blocks found. + ui.heading(RichText::new(ws.num_blocks_found.to_string()) + .color(Colors::TITLE) + .size(16.0)); + }); + ui.horizontal_top(|ui| { + ui.add_space(6.0); + ui.heading(RichText::new(CLOCK_AFTERNOON) + .color(Colors::TITLE) + .size(16.0)); + ui.add_space(4.0); + + // Draw block time + let seen = ws.last_seen.duration_since(std::time::UNIX_EPOCH).unwrap().as_secs(); + let naive_datetime = NaiveDateTime::from_timestamp_opt(seen as i64, 0).unwrap(); + let datetime: DateTime = DateTime::from_utc(naive_datetime, Utc); + ui.heading(RichText::new(datetime.to_string()) + .color(Colors::GRAY) + .size(16.0)); + + }); + ui.add_space(2.0); + }); + }); } \ No newline at end of file diff --git a/src/gui/views/network_node.rs b/src/gui/views/network_node.rs index 10824a4..1bdfbe5 100644 --- a/src/gui/views/network_node.rs +++ b/src/gui/views/network_node.rs @@ -13,7 +13,7 @@ // limitations under the License. use eframe::epaint::Stroke; -use egui::{Color32, RichText, Rounding, ScrollArea}; +use egui::{RichText, Rounding, ScrollArea}; use grin_servers::PeerStats; use crate::gui::Colors; @@ -48,11 +48,8 @@ impl NetworkTab for NetworkNode { ScrollArea::vertical() .auto_shrink([false; 2]) .show(ui, |ui| { - // Show header stats - ui.vertical_centered_justified(|ui| { - View::sub_header(ui, format!("{} {}", FLOW_ARROW, t!("network_node.header"))); - }); - ui.add_space(4.0); + // Show header info. + View::sub_title(ui, format!("{} {}", FLOW_ARROW, t!("network_node.header"))); ui.columns(2, |columns| { columns[0].vertical_centered(|ui| { View::rounded_box(ui, @@ -82,13 +79,10 @@ impl NetworkTab for NetworkNode { [false, false, false, true]); }); }); + ui.add_space(4.0); - // Show block stats - ui.add_space(4.0); - ui.vertical_centered_justified(|ui| { - View::sub_header(ui, format!("{} {}", CUBE, t!("network_node.block"))); - }); - ui.add_space(4.0); + // Show block info. + View::sub_title(ui, format!("{} {}", CUBE, t!("network_node.block"))); ui.columns(2, |columns| { columns[0].vertical_centered(|ui| { View::rounded_box(ui, @@ -118,13 +112,10 @@ impl NetworkTab for NetworkNode { [false, false, false, true]); }); }); + ui.add_space(4.0); - // Show data stats - ui.add_space(4.0); - ui.vertical_centered_justified(|ui| { - View::sub_header(ui, format!("{} {}", SHARE_NETWORK, t!("network_node.data"))); - }); - ui.add_space(4.0); + // Show data info. + View::sub_title(ui, format!("{} {}", SHARE_NETWORK, t!("network_node.data"))); ui.columns(2, |columns| { columns[0].vertical_centered(|ui| { let tx_stat = match &stats.tx_stats { @@ -165,15 +156,11 @@ impl NetworkTab for NetworkNode { [false, false, false, true]); }); }); + ui.add_space(4.0); - // Show peers stats when available + // Show peer stats when available. if stats.peer_count > 0 { - ui.add_space(4.0); - ui.vertical_centered_justified(|ui| { - View::sub_header(ui, format!("{} {}", HANDSHAKE, t!("network_node.peers"))); - }); - ui.add_space(4.0); - + View::sub_title(ui, format!("{} {}", HANDSHAKE, t!("network_node.peers"))); for index in 0..stats.peer_stats.len() { let ps = stats.peer_stats.get(index).unwrap(); let rounding = if stats.peer_count == 1 { @@ -197,7 +184,7 @@ impl NetworkTab for NetworkNode { fn draw_peer_stats(ui: &mut egui::Ui, peer: &PeerStats, rounding: [bool; 2]) { ui.vertical(|ui| { let mut rect = ui.available_rect_before_wrap(); - rect.set_height(77.0); + rect.set_height(78.0); ui.painter().rect( rect, @@ -207,7 +194,7 @@ fn draw_peer_stats(ui: &mut egui::Ui, peer: &PeerStats, rounding: [bool; 2]) { sw: if rounding[1] { 8.0 } else { 0.0 }, se: if rounding[1] { 8.0 } else { 0.0 }, }, - Color32::WHITE, + Colors::WHITE, Stroke { width: 1.0, color: Colors::ITEM_STROKE } ); @@ -255,7 +242,7 @@ fn draw_peer_stats(ui: &mut egui::Ui, peer: &PeerStats, rounding: [bool; 2]) { .color(Colors::GRAY) .size(16.0)); }); - ui.add_space(2.0); + ui.add_space(3.0); }); // Add space after last item diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index af935be..a2d985f 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -18,7 +18,7 @@ use egui::epaint::text::TextWrapping; use egui::text::{LayoutJob, TextFormat}; use crate::gui::Colors; -use crate::gui::icons::{CHECK_SQUARE, SQUARE}; +use crate::gui::icons::{CHECK_SQUARE, CIRCLE, RADIO_BUTTON, SQUARE}; pub struct View; @@ -54,19 +54,23 @@ impl View { ui.label(job); } - /// Sub-header with uppercase characters and more lighter color. - pub fn sub_header(ui: &mut egui::Ui, text: String) { - ui.label(RichText::new(text.to_uppercase()).size(16.0).color(Colors::TEXT)); + /// Draw horizontally centered sub-title with space below. + pub fn sub_title(ui: &mut egui::Ui, text: String) { + ui.vertical_centered_justified(|ui| { + ui.label(RichText::new(text.to_uppercase()).size(16.0).color(Colors::TEXT)); + }); + ui.add_space(4.0); } /// Temporary button click optimization for touch screens. fn on_button_click(ui: &mut egui::Ui, resp: Response, action: impl FnOnce()) { + let drag_resp = resp.interact(Sense::click_and_drag()); // Clear pointer event if dragging is out of button area - if resp.dragged() && !ui.rect_contains_pointer(resp.rect) { + if drag_resp.dragged() && !ui.rect_contains_pointer(drag_resp.rect) { ui.input_mut().pointer = PointerState::default(); } // Call click action if button is clicked or drag released - if resp.drag_released() || resp.clicked() { + if drag_resp.drag_released() || drag_resp.clicked() { (action)(); }; } @@ -80,7 +84,7 @@ impl View { let wt = RichText::new(icon.to_string()).size(24.0).color(Colors::TITLE); let br = Button::new(wt) .fill(Colors::TRANSPARENT) - .ui(ui).interact(Sense::click_and_drag()); + .ui(ui); Self::on_button_click(ui, br, action); }); @@ -106,7 +110,7 @@ impl View { let br = Button::new(wt) .stroke(stroke) .fill(color) - .ui(ui).interact(Sense::click_and_drag()); + .ui(ui); Self::on_button_click(ui, br, action); } @@ -117,7 +121,7 @@ impl View { let br = Button::new(wt) .stroke(Self::DEFAULT_STROKE) .fill(fill_color) - .ui(ui).interact(Sense::click_and_drag()); + .ui(ui); Self::on_button_click(ui, br, action); } @@ -146,25 +150,31 @@ impl View { // Draw box content. let content_resp = ui.allocate_ui_at_rect(rect, |ui| { ui.vertical_centered_justified(|ui| { - // Correct vertical spacing between items. - ui.style_mut().spacing.item_spacing.y = -4.0; + ui.add_space(2.0); - // Draw box value. - let mut job = LayoutJob::single_section(value, TextFormat { - font_id: FontId::proportional(18.0), - color: Colors::BLACK, - ..Default::default() + ui.scope(|ui| { + // Correct vertical spacing between items. + ui.style_mut().spacing.item_spacing.y = -3.0; + + // Draw box value. + let mut job = LayoutJob::single_section(value, TextFormat { + font_id: FontId::proportional(18.0), + color: Colors::BLACK, + ..Default::default() + }); + job.wrap = TextWrapping { + max_rows: 1, + break_anywhere: false, + overflow_character: Option::from('﹍'), + ..Default::default() + }; + ui.label(job); + + // Draw box label. + ui.label(RichText::new(label).color(Colors::GRAY).size(15.0)); }); - job.wrap = TextWrapping { - max_rows: 1, - break_anywhere: false, - overflow_character: Option::from('﹍'), - ..Default::default() - }; - ui.label(job); - // Draw box label. - ui.label(RichText::new(label).color(Colors::GRAY).size(15.0)); + ui.add_space(2.0); }); }).response; @@ -196,18 +206,36 @@ impl View { Spinner::new().size(48.0).color(Colors::GOLD).ui(ui); } - /// Draw the button that looks like checkbox with callback after change. + /// Draw the button that looks like checkbox with callback on check. pub fn checkbox(ui: &mut egui::Ui, checked: bool, text: String, callback: impl FnOnce()) { - let text_value = match checked { - true => { format!("{} {}", CHECK_SQUARE, text)} - false => { format!("{} {}", SQUARE, text)} + let (text_value, color) = match checked { + true => { (format!("{} {}", CHECK_SQUARE, text), Colors::BUTTON) } + false => { (format!("{} {}", SQUARE, text), Colors::TEXT) } }; - let wt = RichText::new(text_value).size(19.0).color(Colors::BUTTON); + + let wt = RichText::new(text_value).size(18.0).color(color); let br = Button::new(wt) .frame(false) .stroke(Stroke::NONE) .fill(Colors::TRANSPARENT) - .ui(ui).interact(Sense::click_and_drag()); + .ui(ui); + + Self::on_button_click(ui, br, callback); + } + + /// Draw the radio button with callback on select. + pub fn radio_button(ui: &mut egui::Ui, selected: bool, text: String, callback: impl FnOnce()) { + let (text_value, color) = match selected { + true => { (format!("{} {}", RADIO_BUTTON, text), Colors::BUTTON) } + false => { (format!("{} {}", CIRCLE, text), Colors::TEXT) } + }; + + let wt = RichText::new(text_value).size(18.0).color(color); + let br = Button::new(wt) + .frame(false) + .stroke(Stroke::NONE) + .fill(Colors::TRANSPARENT) + .ui(ui); Self::on_button_click(ui, br, callback); } diff --git a/src/node/node.rs b/src/node/node.rs index e5c5549..c1838b3 100644 --- a/src/node/node.rs +++ b/src/node/node.rs @@ -186,7 +186,7 @@ impl Node { server.start_stratum_server(stratum_config); // Wait for mining server to start and update status. - thread::sleep(Duration::from_millis(1000)); + thread::sleep(Duration::from_millis(100)); NODE_STATE.start_stratum_server.store(false, Ordering::Relaxed); }