Present Servo BGRA hardware surfaces
This commit is contained in:
+231
@@ -0,0 +1,231 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
use futures::channel::oneshot;
|
||||
|
||||
use crate::{
|
||||
AnyView, App, AppContext as _, Context, Entity, EventEmitter, FocusHandle, Focusable,
|
||||
InteractiveElement, IntoElement, ParentElement, PromptButton, PromptLevel, Render,
|
||||
StatefulInteractiveElement, Styled, div, opaque_grey, white,
|
||||
};
|
||||
|
||||
use super::Window;
|
||||
|
||||
/// The event emitted when a prompt's option is selected.
|
||||
/// The usize is the index of the selected option, from the actions
|
||||
/// passed to the prompt.
|
||||
pub struct PromptResponse(pub usize);
|
||||
|
||||
/// A prompt that can be rendered in the window.
|
||||
pub trait Prompt: EventEmitter<PromptResponse> + Focusable {}
|
||||
|
||||
impl<V: EventEmitter<PromptResponse> + Focusable> Prompt for V {}
|
||||
|
||||
/// A handle to a prompt that can be used to interact with it.
|
||||
pub struct PromptHandle {
|
||||
sender: oneshot::Sender<usize>,
|
||||
}
|
||||
|
||||
impl PromptHandle {
|
||||
pub(crate) fn new(sender: oneshot::Sender<usize>) -> Self {
|
||||
Self { sender }
|
||||
}
|
||||
|
||||
/// Construct a new prompt handle from a view of the appropriate types
|
||||
pub fn with_view<V: Prompt + Render>(
|
||||
self,
|
||||
view: Entity<V>,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> RenderablePromptHandle {
|
||||
let mut sender = Some(self.sender);
|
||||
let previous_focus = window.focused(cx);
|
||||
let window_handle = window.window_handle();
|
||||
cx.subscribe(&view, move |_: Entity<V>, e: &PromptResponse, cx| {
|
||||
if let Some(sender) = sender.take() {
|
||||
sender.send(e.0).ok();
|
||||
window_handle
|
||||
.update(cx, |_, window, _cx| {
|
||||
window.prompt.take();
|
||||
if let Some(previous_focus) = &previous_focus {
|
||||
window.focus(previous_focus);
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
window.focus(&view.focus_handle(cx));
|
||||
|
||||
RenderablePromptHandle {
|
||||
view: Box::new(view),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A prompt handle capable of being rendered in a window.
|
||||
pub struct RenderablePromptHandle {
|
||||
pub(crate) view: Box<dyn PromptViewHandle>,
|
||||
}
|
||||
|
||||
/// Use this function in conjunction with [App::set_prompt_builder] to force
|
||||
/// GPUI to always use the fallback prompt renderer.
|
||||
pub fn fallback_prompt_renderer(
|
||||
level: PromptLevel,
|
||||
message: &str,
|
||||
detail: Option<&str>,
|
||||
actions: &[PromptButton],
|
||||
handle: PromptHandle,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) -> RenderablePromptHandle {
|
||||
let renderer = cx.new(|cx| FallbackPromptRenderer {
|
||||
_level: level,
|
||||
message: message.to_string(),
|
||||
detail: detail.map(ToString::to_string),
|
||||
actions: actions.to_vec(),
|
||||
focus: cx.focus_handle(),
|
||||
});
|
||||
|
||||
handle.with_view(renderer, window, cx)
|
||||
}
|
||||
|
||||
/// The default GPUI fallback for rendering prompts, when the platform doesn't support it.
|
||||
pub struct FallbackPromptRenderer {
|
||||
_level: PromptLevel,
|
||||
message: String,
|
||||
detail: Option<String>,
|
||||
actions: Vec<PromptButton>,
|
||||
focus: FocusHandle,
|
||||
}
|
||||
|
||||
impl Render for FallbackPromptRenderer {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let prompt = div()
|
||||
.cursor_default()
|
||||
.track_focus(&self.focus)
|
||||
.w_72()
|
||||
.bg(white())
|
||||
.rounded_lg()
|
||||
.overflow_hidden()
|
||||
.p_3()
|
||||
.child(
|
||||
div()
|
||||
.w_full()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.justify_around()
|
||||
.child(div().overflow_hidden().child(self.message.clone())),
|
||||
)
|
||||
.children(self.detail.clone().map(|detail| {
|
||||
div()
|
||||
.w_full()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.justify_around()
|
||||
.text_sm()
|
||||
.mb_2()
|
||||
.child(div().child(detail))
|
||||
}))
|
||||
.children(self.actions.iter().enumerate().map(|(ix, action)| {
|
||||
div()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.justify_around()
|
||||
.border_1()
|
||||
.border_color(opaque_grey(0.2, 0.5))
|
||||
.mt_1()
|
||||
.rounded_xs()
|
||||
.cursor_pointer()
|
||||
.text_sm()
|
||||
.child(action.label().clone())
|
||||
.id(ix)
|
||||
.on_click(cx.listener(move |_, _, _, cx| {
|
||||
cx.emit(PromptResponse(ix));
|
||||
}))
|
||||
}));
|
||||
|
||||
div()
|
||||
.size_full()
|
||||
.child(
|
||||
div()
|
||||
.size_full()
|
||||
.bg(opaque_grey(0.5, 0.6))
|
||||
.absolute()
|
||||
.top_0()
|
||||
.left_0(),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.size_full()
|
||||
.absolute()
|
||||
.top_0()
|
||||
.left_0()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.justify_around()
|
||||
.child(
|
||||
div()
|
||||
.w_full()
|
||||
.flex()
|
||||
.flex_row()
|
||||
.justify_around()
|
||||
.child(prompt),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<PromptResponse> for FallbackPromptRenderer {}
|
||||
|
||||
impl Focusable for FallbackPromptRenderer {
|
||||
fn focus_handle(&self, _: &crate::App) -> FocusHandle {
|
||||
self.focus.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait PromptViewHandle {
|
||||
fn any_view(&self) -> AnyView;
|
||||
}
|
||||
|
||||
impl<V: Prompt + Render> PromptViewHandle for Entity<V> {
|
||||
fn any_view(&self) -> AnyView {
|
||||
self.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) enum PromptBuilder {
|
||||
Default,
|
||||
Custom(
|
||||
Box<
|
||||
dyn Fn(
|
||||
PromptLevel,
|
||||
&str,
|
||||
Option<&str>,
|
||||
&[PromptButton],
|
||||
PromptHandle,
|
||||
&mut Window,
|
||||
&mut App,
|
||||
) -> RenderablePromptHandle,
|
||||
>,
|
||||
),
|
||||
}
|
||||
|
||||
impl Deref for PromptBuilder {
|
||||
type Target = dyn Fn(
|
||||
PromptLevel,
|
||||
&str,
|
||||
Option<&str>,
|
||||
&[PromptButton],
|
||||
PromptHandle,
|
||||
&mut Window,
|
||||
&mut App,
|
||||
) -> RenderablePromptHandle;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
match self {
|
||||
Self::Default => &fallback_prompt_renderer,
|
||||
Self::Custom(f) => f.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user