From a31d38dc1c428235b9855479c61e3e5fbb0301d2 Mon Sep 17 00:00:00 2001 From: ardocrat Date: Sun, 30 Jul 2023 10:52:24 +0300 Subject: [PATCH] ui: add list item button --- src/gui/colors.rs | 1 + src/gui/views/network/setup/p2p.rs | 132 +++++++++++++++++++---------- src/gui/views/views.rs | 87 ++++++++++++++----- 3 files changed, 151 insertions(+), 69 deletions(-) diff --git a/src/gui/colors.rs b/src/gui/colors.rs index 0b822fc..a804c36 100644 --- a/src/gui/colors.rs +++ b/src/gui/colors.rs @@ -36,4 +36,5 @@ impl Colors { pub const STROKE: Color32 = Color32::from_gray(190); pub const INACTIVE_TEXT: Color32 = Color32::from_gray(150); pub const ITEM_STROKE: Color32 = Color32::from_gray(220); + pub const ITEM_HOVER_STROKE: Color32 = Color32::from_gray(205); } diff --git a/src/gui/views/network/setup/p2p.rs b/src/gui/views/network/setup/p2p.rs index 23bff45..c0a7814 100644 --- a/src/gui/views/network/setup/p2p.rs +++ b/src/gui/views/network/setup/p2p.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Id, RichText, Rounding, TextStyle, Ui, Widget}; +use egui::{Align, Id, Layout, RichText, Rounding, TextStyle, Ui, Widget}; use egui_extras::{Size, StripBuilder}; use grin_core::global::ChainTypes; @@ -474,58 +474,96 @@ impl P2PSetup { /// Draw peer list item. fn peer_item_ui(ui: &mut Ui, peer_addr: &String, peer_type: &PeerType, rounding: Rounding) { - // Draw round background. + // Setup layout size. let mut rect = ui.available_rect_before_wrap(); - rect.min += egui::emath::vec2(6.0, 0.0); rect.set_height(42.0); - ui.painter().rect(rect, rounding, Colors::WHITE, View::ITEM_STROKE); - StripBuilder::new(ui) - .size(Size::exact(42.0)) - .vertical(|mut strip| { - strip.strip(|builder| { - builder - .size(Size::exact(13.0)) - .size(Size::remainder()) - .size(Size::exact(46.0)) - .horizontal(|mut strip| { - strip.empty(); - strip.cell(|ui| { - ui.horizontal_centered(|ui| { - // Draw peer address. - let peer_text = format!("{} {}", COMPUTER_TOWER, &peer_addr); - ui.label(RichText::new(peer_text) - .color(Colors::TEXT_BUTTON) - .size(16.0)); - }); - }); - if peer_type != &PeerType::DefaultSeed { - strip.cell(|ui| { - // Draw delete button for non-default seed peers. - View::button(ui, TRASH.to_string(), Colors::BUTTON, || { - match peer_type { - PeerType::CustomSeed => { - NodeConfig::remove_custom_seed(peer_addr); - } - PeerType::Allowed => { - NodeConfig::remove_allowed_peer(peer_addr); - } - PeerType::Denied => { - NodeConfig::remove_denied_peer(peer_addr); - } - PeerType::Preferred => { - NodeConfig::remove_preferred_peer(peer_addr); - } - PeerType::DefaultSeed => {} - } - }); - }); - } else { - strip.empty(); + // Draw round background. + let mut bg_rect = rect.clone(); + bg_rect.min += egui::emath::vec2(6.0, 0.0); + ui.painter().rect(bg_rect, rounding, Colors::WHITE, View::ITEM_STROKE); + + ui.vertical(|ui| { + ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { + // Draw delete button for non-default seed peers. + if peer_type != &PeerType::DefaultSeed { + View::item_button(ui, [false, true], TRASH, || { + match peer_type { + PeerType::CustomSeed => { + NodeConfig::remove_custom_seed(peer_addr); } - }); + PeerType::Allowed => { + NodeConfig::remove_allowed_peer(peer_addr); + } + PeerType::Denied => { + NodeConfig::remove_denied_peer(peer_addr); + } + PeerType::Preferred => { + NodeConfig::remove_preferred_peer(peer_addr); + } + PeerType::DefaultSeed => {} + } + }); + } + + let layout_size = ui.available_size(); + ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| { + ui.add_space(12.0); + // Draw peer address. + let peer_text = format!("{} {}", COMPUTER_TOWER, &peer_addr); + ui.label(RichText::new(peer_text) + .color(Colors::TEXT_BUTTON) + .size(16.0)); }); }); + }); + + // StripBuilder::new(ui) + // .size(Size::exact(42.0)) + // .vertical(|mut strip| { + // strip.strip(|builder| { + // builder + // .size(Size::exact(13.0)) + // .size(Size::remainder()) + // .size(Size::exact(42.0)) + // .horizontal(|mut strip| { + // strip.empty(); + // strip.cell(|ui| { + // ui.horizontal_centered(|ui| { + // // Draw peer address. + // let peer_text = format!("{} {}", COMPUTER_TOWER, &peer_addr); + // ui.label(RichText::new(peer_text) + // .color(Colors::TEXT_BUTTON) + // .size(16.0)); + // }); + // }); + // if peer_type != &PeerType::DefaultSeed { + // strip.cell(|ui| { + // // Draw delete button for non-default seed peers. + // View::item_button(ui, [false, true], TRASH, || { + // match peer_type { + // PeerType::CustomSeed => { + // NodeConfig::remove_custom_seed(peer_addr); + // } + // PeerType::Allowed => { + // NodeConfig::remove_allowed_peer(peer_addr); + // } + // PeerType::Denied => { + // NodeConfig::remove_denied_peer(peer_addr); + // } + // PeerType::Preferred => { + // NodeConfig::remove_preferred_peer(peer_addr); + // } + // PeerType::DefaultSeed => {} + // } + // }); + // }); + // } else { + // strip.empty(); + // } + // }); + // }); + // }); } /// Draw seeding type setup content. diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index 9d2f44f..026045b 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -30,6 +30,8 @@ impl View { pub const DEFAULT_STROKE: Stroke = Stroke { width: 1.0, color: Colors::STROKE }; /// Stroke around list items. pub const ITEM_STROKE: Stroke = Stroke { width: 1.0, color: Colors::ITEM_STROKE }; + /// Stroke around list items. + pub const ITEM_HOVER_STROKE: Stroke = Stroke { width: 1.0, color: Colors::ITEM_HOVER_STROKE }; /// Callback on Enter key press event. pub fn on_enter_key(ui: &mut egui::Ui, cb: impl FnOnce()) { @@ -102,12 +104,16 @@ impl View { /// Title button with transparent background fill color, contains only icon. pub fn title_button(ui: &mut egui::Ui, icon: &str, action: impl FnOnce()) { ui.scope(|ui| { - // Disable stroke around title buttons on click. - ui.style_mut().visuals.widgets.active.bg_stroke = Stroke::NONE; - // Disable rounding on hover. + // Setup stroke around title buttons on click. + ui.style_mut().visuals.widgets.hovered.bg_stroke = Self::ITEM_HOVER_STROKE; + ui.style_mut().visuals.widgets.active.bg_stroke = Self::DEFAULT_STROKE; + // Disable rounding. ui.style_mut().visuals.widgets.hovered.rounding = Rounding::none(); - // Disable stroke color on hover. - ui.style_mut().visuals.widgets.hovered.bg_stroke = Self::DEFAULT_STROKE; + ui.style_mut().visuals.widgets.active.rounding = Rounding::none(); + // Disable expansion. + ui.style_mut().visuals.widgets.hovered.expansion = 0.0; + ui.style_mut().visuals.widgets.active.expansion = 0.0; + // Setup text. let wt = RichText::new(icon.to_string()).size(22.0).color(Colors::TITLE); // Draw button. @@ -156,14 +162,12 @@ impl View { } /// Draw round [`Button`] with icon. - pub fn round_button(ui: &mut egui::Ui, - icon: &'static str, - action: impl FnOnce()) { + pub fn round_button(ui: &mut egui::Ui, icon: &'static str, action: impl FnOnce()) { ui.scope(|ui| { // Setup colors. ui.visuals_mut().widgets.inactive.bg_fill = Colors::BUTTON; - ui.visuals_mut().widgets.hovered.bg_fill = Colors::GOLD; - ui.visuals_mut().widgets.active.bg_fill = Colors::YELLOW; + ui.visuals_mut().widgets.hovered.bg_fill = Colors::FILL; + ui.visuals_mut().widgets.active.bg_fill = Colors::FILL_DARK; // Setup radius. let mut r = 44.0 * 0.5; @@ -174,7 +178,7 @@ impl View { // Increase radius and change icon size and color on-hover. if br.hovered() { - r = r * 1.07; + r = r * 1.05; icon_color = Colors::TEXT_BUTTON; } @@ -196,24 +200,63 @@ impl View { }); } + /// Draw list item [`Button`] with given vertical padding and rounding on left and right sides. + pub fn item_button(ui: &mut egui::Ui, r: [bool; 2], icon: &'static str, action: impl FnOnce()) { + let rounding = Self::get_rounding([r[0], r[1], r[1], r[0]]); + + // Setup button size. + let mut rect = ui.available_rect_before_wrap(); + rect.set_width(32.0); + let button_size = rect.size(); + + ui.scope(|ui| { + // Disable expansion on click/hover. + ui.style_mut().visuals.widgets.hovered.expansion = 0.0; + ui.style_mut().visuals.widgets.active.expansion = 0.0; + + // Setup fill colors. + ui.visuals_mut().widgets.inactive.weak_bg_fill = Colors::WHITE; + ui.visuals_mut().widgets.hovered.weak_bg_fill = Colors::BUTTON; + ui.visuals_mut().widgets.active.weak_bg_fill = Colors::FILL; + + // Setup stroke colors. + ui.visuals_mut().widgets.inactive.bg_stroke = Self::DEFAULT_STROKE; + ui.visuals_mut().widgets.hovered.bg_stroke = Self::ITEM_HOVER_STROKE; + ui.visuals_mut().widgets.active.bg_stroke = Self::ITEM_STROKE; + + // Show button. + let br = Button::new(RichText::new(icon).size(20.0).color(Colors::CHECKBOX)) + .rounding(rounding) + .min_size(button_size) + .ui(ui); + if Self::touched(ui, br) { + (action)(); + } + }); + } + + /// Get rounding for provided corners clockwise. + fn get_rounding(corners: [bool; 4]) -> Rounding { + Rounding { + nw: if corners[0] { 8.0 } else { 0.0 }, + ne: if corners[1] { 8.0 } else { 0.0 }, + sw: if corners[3] { 8.0 } else { 0.0 }, + se: if corners[2] { 8.0 } else { 0.0 }, + } + } + /// Calculate list item rounding based on item index. pub fn item_rounding(index: usize, len: usize) -> Rounding { let rounding = if len == 1 { - [true, true] + [true, true, true, true] } else if index == 0 { - [true, false] + [true, true, false, false] } else if index == len - 1 { - [false, true] + [false, false, true, true] } else { - [false, false] + [false, false, false, false] }; - - 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 }, - } + Self::get_rounding(rounding) } /// Draw rounded box with some value and label in the middle,