From d5dcc87ace706d9083e8744f716acebcca44b955 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 5 Feb 2023 21:57:40 +0100 Subject: [PATCH] Improve custom_window_frame --- examples/custom_window_frame/src/main.rs | 209 ++++++++++++----------- 1 file changed, 111 insertions(+), 98 deletions(-) diff --git a/examples/custom_window_frame/src/main.rs b/examples/custom_window_frame/src/main.rs index 87813ae2..4c07416f 100644 --- a/examples/custom_window_frame/src/main.rs +++ b/examples/custom_window_frame/src/main.rs @@ -31,7 +31,7 @@ impl eframe::App for MyApp { fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { custom_window_frame(ctx, frame, "egui with custom frame", |ui| { - ui.label("This is just the contents of the window"); + 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); @@ -47,105 +47,118 @@ fn custom_window_frame( 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; + let panel_frame = egui::Frame { + fill: ctx.style().visuals.window_fill(), + rounding: 10.0.into(), + stroke: ctx.style().visuals.widgets.noninteractive.fg_stroke, + outer_margin: 0.5.into(), // so the stroke is within the bounds + ..Default::default() + }; - let button_height = 16.0; + CentralPanel::default().frame(panel_frame).show(ctx, |ui| { + let app_rect = ui.max_rect(); - CentralPanel::default() - .frame(Frame::none()) - .show(ctx, |ui| { - let rect = ui.max_rect(); - let painter = ui.painter(); + let title_bar_height = 32.0; + let title_bar_rect = { + let mut rect = app_rect; + rect.max.y = rect.min.y + title_bar_height; + rect + }; + title_bar_ui(ui, frame, title_bar_rect, title); - // 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 * 0.8), - 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), - ); - - // 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::click()); - - if title_bar_response.double_clicked() { - frame.set_maximized(!frame.info().window_info.maximized); - } else if title_bar_response.is_pointer_button_down_on() { - frame.drag_window(); - } - - ui.allocate_ui_at_rect(title_bar_rect, |ui| { - ui.horizontal_centered(|ui| { - ui.spacing_mut().item_spacing.x = 0.0; - ui.visuals_mut().button_frame = false; - - let close_response = ui - .add(Button::new(RichText::new("❌").size(button_height))) - .on_hover_text("Close the window"); - if close_response.clicked() { - frame.close(); - } - - let minimized_response = ui - .add(Button::new(RichText::new("🗕").size(button_height))) - .on_hover_text("Minimize the window"); - if minimized_response.clicked() { - frame.set_minimized(true); - } - - if frame.info().window_info.maximized { - let maximized_response = ui - .add(Button::new(RichText::new("🗖").size(button_height))) - .on_hover_text("Restore window"); - if maximized_response.clicked() { - frame.set_maximized(false); - } - } else { - let maximized_response = ui - .add(Button::new(RichText::new("🗗").size(button_height))) - .on_hover_text("Maximize window"); - if maximized_response.clicked() { - frame.set_maximized(true); - } - } - }); - }); - - // 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); - }); + // Add the contents: + let content_rect = { + let mut rect = app_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); + }); +} + +fn title_bar_ui( + ui: &mut egui::Ui, + frame: &mut eframe::Frame, + title_bar_rect: eframe::epaint::Rect, + title: &str, +) { + use egui::*; + + let painter = ui.painter(); + + let title_bar_response = ui.interact(title_bar_rect, Id::new("title_bar"), Sense::click()); + + // Paint the title: + painter.text( + title_bar_rect.center(), + Align2::CENTER_CENTER, + title, + FontId::proportional(20.0), + ui.style().visuals.text_color(), + ); + + // Paint the line under the title: + painter.line_segment( + [ + title_bar_rect.left_bottom() + vec2(1.0, 0.0), + title_bar_rect.right_bottom() + vec2(-1.0, 0.0), + ], + ui.visuals().widgets.noninteractive.bg_stroke, + ); + + // Interact with the title bar (drag to move window): + if title_bar_response.double_clicked() { + frame.set_maximized(!frame.info().window_info.maximized); + } else if title_bar_response.is_pointer_button_down_on() { + frame.drag_window(); + } + + ui.allocate_ui_at_rect(title_bar_rect, |ui| { + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + ui.spacing_mut().item_spacing.x = 0.0; + ui.visuals_mut().button_frame = false; + ui.add_space(8.0); + close_maximize_minimize(ui, frame); + }); + }); +} + +/// Show some close/maximize/minimize buttons for the native window. +fn close_maximize_minimize(ui: &mut egui::Ui, frame: &mut eframe::Frame) { + use egui::{Button, RichText}; + + let button_height = 12.0; + + let close_response = ui + .add(Button::new(RichText::new("❌").size(button_height))) + .on_hover_text("Close the window"); + if close_response.clicked() { + frame.close(); + } + + if frame.info().window_info.maximized { + let maximized_response = ui + .add(Button::new(RichText::new("🗗").size(button_height))) + .on_hover_text("Restore window"); + if maximized_response.clicked() { + frame.set_maximized(false); + } + } else { + let maximized_response = ui + .add(Button::new(RichText::new("🗗").size(button_height))) + .on_hover_text("Maximize window"); + if maximized_response.clicked() { + frame.set_maximized(true); + } + } + + let minimized_response = ui + .add(Button::new(RichText::new("🗕").size(button_height))) + .on_hover_text("Minimize the window"); + if minimized_response.clicked() { + frame.set_minimized(true); + } }