From 805539b50d1afdbc05518ef05e828c7638fdfacc Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Mon, 21 Mar 2022 22:20:58 +0100 Subject: [PATCH] Add example of custom window frame for native window using eframe (#1396) --- eframe/examples/custom_window_frame.rs | 117 +++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 eframe/examples/custom_window_frame.rs diff --git a/eframe/examples/custom_window_frame.rs b/eframe/examples/custom_window_frame.rs new file mode 100644 index 00000000..9f5dd222 --- /dev/null +++ b/eframe/examples/custom_window_frame.rs @@ -0,0 +1,117 @@ +//! Show a custom window frame instead of the default OS window chrome decorations. + +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release + +use eframe::egui; + +fn main() { + let options = eframe::NativeOptions { + // Hide the OS-specific "chrome" around the window: + decorated: false, + // To have rounded corners we need transparency: + transparent: true, + min_window_size: Some(egui::vec2(320.0, 100.0)), + ..Default::default() + }; + eframe::run_native( + "Custom window frame", // unused title + options, + Box::new(|_cc| Box::new(MyApp::default())), + ); +} + +#[derive(Default)] +struct MyApp {} + +impl eframe::App for MyApp { + fn clear_color(&self) -> egui::Rgba { + egui::Rgba::TRANSPARENT // Make sure we don't paint anything behind the rounded corners + } + + fn update(&mut self, ctx: &egui::Context, frame: &eframe::Frame) { + custon_window_frame(ctx, frame, "egui with custom frame", |ui| { + ui.label("This is just the contents of the window"); + ui.horizontal(|ui| { + ui.label("egui theme:"); + egui::widgets::global_dark_light_mode_buttons(ui); + }); + }); + } +} + +fn custon_window_frame( + ctx: &egui::Context, + frame: &eframe::Frame, + title: &str, + add_contents: impl FnOnce(&mut egui::Ui), +) { + use egui::*; + let text_color = ctx.style().visuals.text_color(); + + // Height of the title bar + let height = 28.0; + + CentralPanel::default() + .frame(Frame::none()) + .show(ctx, |ui| { + let rect = ui.max_rect(); + let painter = ui.painter(); + + // Paint the frame: + painter.rect( + rect.shrink(1.0), + 10.0, + ctx.style().visuals.window_fill(), + Stroke::new(1.0, text_color), + ); + + // Paint the title: + painter.text( + rect.center_top() + vec2(0.0, height / 2.0), + Align2::CENTER_CENTER, + title, + FontId::proportional(height - 2.0), + text_color, + ); + + // Paint the line under the title: + painter.line_segment( + [ + rect.left_top() + vec2(2.0, height), + rect.right_top() + vec2(-2.0, height), + ], + Stroke::new(1.0, text_color), + ); + + // Add the close button: + let close_response = ui.put( + Rect::from_min_size(rect.left_top(), Vec2::splat(height)), + Button::new(RichText::new("❌").size(height - 4.0)).frame(false), + ); + if close_response.clicked() { + frame.quit(); + } + + // Interact with the title bar (drag to move window): + let title_bar_rect = { + let mut rect = rect; + rect.max.y = rect.min.y + height; + rect + }; + let title_bar_response = + ui.interact(title_bar_rect, Id::new("title_bar"), Sense::drag()); + if title_bar_response.drag_started() { + frame.drag_window(); + } + + // Add the contents: + let content_rect = { + let mut rect = rect; + rect.min.y = title_bar_rect.max.y; + rect + } + .shrink(4.0); + let mut content_ui = ui.child_ui(content_rect, *ui.layout()); + add_contents(&mut content_ui); + }); +}