mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
servoshell: Add close buttons and increase interactivity of tabs (#33244)
* Improved the minibrowser tab bar Added a close button for each tab as well as another button for opening a new tab, also changed the styling so it looks more like other browsers. Signed-off-by: Benjamin Vincent Schulenburg <bennyschulenburg@gmx.de> * Make sure to restore the egui visuals after drawing a browser tab Signed-off-by: Benjamin Vincent Schulenburg <bennyschulenburg@gmx.de> * Only use colors from the current theme for the minibrowser tabbar That way we can easily switch between light and dark mode Signed-off-by: Benjamin Vincent Schulenburg <bennyschulenburg@gmx.de> --------- Signed-off-by: Benjamin Vincent Schulenburg <bennyschulenburg@gmx.de>
This commit is contained in:
parent
3c6ca33832
commit
891562be8e
1 changed files with 103 additions and 18 deletions
|
@ -10,8 +10,8 @@ use std::time::Instant;
|
|||
use egui::text::{CCursor, CCursorRange};
|
||||
use egui::text_edit::TextEditState;
|
||||
use egui::{
|
||||
pos2, CentralPanel, Color32, Frame, Key, Label, Modifiers, PaintCallback, Pos2,
|
||||
SelectableLabel, TopBottomPanel, Vec2,
|
||||
pos2, CentralPanel, Frame, Key, Label, Modifiers, PaintCallback, Pos2, SelectableLabel,
|
||||
TopBottomPanel, Vec2,
|
||||
};
|
||||
use egui_glow::CallbackFn;
|
||||
use egui_winit::EventResponse;
|
||||
|
@ -19,12 +19,14 @@ use euclid::{Box2D, Length, Point2D, Scale, Size2D};
|
|||
use gleam::gl;
|
||||
use glow::NativeFramebuffer;
|
||||
use log::{trace, warn};
|
||||
use servo::base::id::WebViewId;
|
||||
use servo::compositing::windowing::EmbedderEvent;
|
||||
use servo::script_traits::TraversalDirection;
|
||||
use servo::servo_geometry::DeviceIndependentPixel;
|
||||
use servo::servo_url::ServoUrl;
|
||||
use servo::style_traits::DevicePixel;
|
||||
use servo::webrender_traits::RenderingContext;
|
||||
use servo::TopLevelBrowsingContextId;
|
||||
use winit::event::{ElementState, MouseButton};
|
||||
|
||||
use super::egui_glue::EguiGlow;
|
||||
|
@ -61,6 +63,7 @@ pub enum MinibrowserEvent {
|
|||
Back,
|
||||
Forward,
|
||||
Reload,
|
||||
NewWebView,
|
||||
}
|
||||
|
||||
fn truncate_with_ellipsis(input: &str, max_length: usize) -> String {
|
||||
|
@ -163,6 +166,87 @@ impl Minibrowser {
|
|||
.min_size(Vec2 { x: 20.0, y: 20.0 })
|
||||
}
|
||||
|
||||
/// Draws a browser tab, checking for clicks and returns an appropriate [EmbedderEvent]
|
||||
/// Using a custom widget here would've been nice, but it doesn't seem as though egui
|
||||
/// supports that, so we arrange multiple Widgets in a way that they look connected.
|
||||
fn browser_tab(
|
||||
ui: &mut egui::Ui,
|
||||
label: &str,
|
||||
selected: bool,
|
||||
webview_id: TopLevelBrowsingContextId,
|
||||
) -> Option<EmbedderEvent> {
|
||||
let old_item_spacing = ui.spacing().item_spacing;
|
||||
let old_visuals = ui.visuals().clone();
|
||||
let active_bg_color = old_visuals.widgets.active.weak_bg_fill;
|
||||
let inactive_bg_color = old_visuals.window_fill;
|
||||
ui.spacing_mut().item_spacing = egui::vec2(0.0, 0.0);
|
||||
|
||||
let visuals = ui.visuals_mut();
|
||||
// Remove the stroke so we don't see the border between the close button and the label
|
||||
visuals.widgets.active.bg_stroke.width = 0.0;
|
||||
visuals.widgets.hovered.bg_stroke.width = 0.0;
|
||||
// Now we make sure the fill color is always the same, irrespective of state, that way
|
||||
// we can make sure that both the label and close button have the same background color
|
||||
visuals.widgets.noninteractive.weak_bg_fill = inactive_bg_color;
|
||||
visuals.widgets.inactive.weak_bg_fill = inactive_bg_color;
|
||||
visuals.widgets.hovered.weak_bg_fill = active_bg_color;
|
||||
visuals.widgets.active.weak_bg_fill = active_bg_color;
|
||||
visuals.selection.bg_fill = active_bg_color;
|
||||
visuals.selection.stroke.color = visuals.widgets.active.fg_stroke.color;
|
||||
visuals.widgets.hovered.fg_stroke.color = visuals.widgets.active.fg_stroke.color;
|
||||
|
||||
// Expansion would also show that they are 2 separate widgets
|
||||
visuals.widgets.active.expansion = 0.0;
|
||||
visuals.widgets.hovered.expansion = 0.0;
|
||||
// The rounding is changed so it looks as though the 2 widgets are a single widget
|
||||
// with a uniform rounding
|
||||
let rounding = egui::Rounding {
|
||||
ne: 0.0,
|
||||
nw: 4.0,
|
||||
sw: 4.0,
|
||||
se: 0.0,
|
||||
};
|
||||
visuals.widgets.active.rounding = rounding;
|
||||
visuals.widgets.hovered.rounding = rounding;
|
||||
visuals.widgets.inactive.rounding = rounding;
|
||||
|
||||
let tab = ui.add(SelectableLabel::new(
|
||||
selected,
|
||||
truncate_with_ellipsis(label, 20),
|
||||
));
|
||||
let tab = tab.on_hover_ui(|ui| {
|
||||
ui.label(label);
|
||||
});
|
||||
|
||||
let rounding = egui::Rounding {
|
||||
ne: 4.0,
|
||||
nw: 0.0,
|
||||
sw: 0.0,
|
||||
se: 4.0,
|
||||
};
|
||||
let visuals = ui.visuals_mut();
|
||||
visuals.widgets.active.rounding = rounding;
|
||||
visuals.widgets.hovered.rounding = rounding;
|
||||
visuals.widgets.inactive.rounding = rounding;
|
||||
|
||||
let fill_color = if selected || tab.hovered() {
|
||||
active_bg_color
|
||||
} else {
|
||||
inactive_bg_color
|
||||
};
|
||||
|
||||
ui.spacing_mut().item_spacing = old_item_spacing;
|
||||
let close_button = ui.add(egui::Button::new("X").fill(fill_color));
|
||||
*ui.visuals_mut() = old_visuals;
|
||||
if close_button.clicked() || close_button.middle_clicked() || tab.middle_clicked() {
|
||||
Some(EmbedderEvent::CloseWebView(webview_id))
|
||||
} else if !selected && tab.clicked() {
|
||||
Some(EmbedderEvent::FocusWebView(webview_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the minibrowser, but don’t paint.
|
||||
/// If `servo_framebuffer_id` is given, set up a paint callback to blit its contents to our
|
||||
/// CentralPanel when [`Minibrowser::paint`] is called.
|
||||
|
@ -195,7 +279,7 @@ impl Minibrowser {
|
|||
// when not displaying the URL bar: https://github.com/servo/servo/issues/32443
|
||||
if window.fullscreen().is_none() {
|
||||
let frame = egui::Frame::default()
|
||||
.fill(Color32::from_gray(32))
|
||||
.fill(ctx.style().visuals.window_fill)
|
||||
.inner_margin(4.0);
|
||||
TopBottomPanel::top("toolbar").frame(frame).show(ctx, |ui| {
|
||||
ui.allocate_ui_with_layout(
|
||||
|
@ -267,30 +351,27 @@ impl Minibrowser {
|
|||
|
||||
let mut embedder_events = vec![];
|
||||
|
||||
// A simple Tab header strip, using egui 'SelectableLabel' elements.
|
||||
// TODO: Add a way to close a tab eg. with a [x] control.
|
||||
// A simple Tab header strip
|
||||
TopBottomPanel::top("tabs").show(ctx, |ui| {
|
||||
ui.allocate_ui_with_layout(
|
||||
ui.available_size(),
|
||||
egui::Layout::left_to_right(egui::Align::Center),
|
||||
|ui| {
|
||||
for (webview_id, webview) in webviews.webviews().into_iter() {
|
||||
let msg = match (&webview.title, &webview.url) {
|
||||
(Some(title), _) if !title.is_empty() => title.clone(),
|
||||
(_, Some(url)) => url.to_string(),
|
||||
_ => "New Tab".to_owned(),
|
||||
let label = match (&webview.title, &webview.url) {
|
||||
(Some(title), _) => title,
|
||||
(None, Some(url)) => &url.to_string(),
|
||||
_ => "New Tab",
|
||||
};
|
||||
let tab = ui.add(SelectableLabel::new(
|
||||
webview.focused,
|
||||
truncate_with_ellipsis(&msg, 20),
|
||||
));
|
||||
let tab = tab.on_hover_ui(|ui| {
|
||||
ui.label(&msg);
|
||||
});
|
||||
if !webview.focused && tab.clicked() {
|
||||
embedder_events.push(EmbedderEvent::FocusWebView(webview_id));
|
||||
if let Some(event) =
|
||||
Self::browser_tab(ui, label, webview.focused, webview_id)
|
||||
{
|
||||
embedder_events.push(event);
|
||||
}
|
||||
}
|
||||
if ui.add(Minibrowser::toolbar_button("+")).clicked() {
|
||||
event_queue.borrow_mut().push(MinibrowserEvent::NewWebView);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -441,6 +522,10 @@ impl Minibrowser {
|
|||
let browser_id = browser.focused_webview_id().unwrap();
|
||||
app_event_queue.push(EmbedderEvent::Reload(browser_id));
|
||||
},
|
||||
MinibrowserEvent::NewWebView => {
|
||||
let url = ServoUrl::parse("servo:newtab").unwrap();
|
||||
app_event_queue.push(EmbedderEvent::NewWebView(url, WebViewId::new()));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue