mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-05 10:20:51 +00:00
WIP
This commit is contained in:
parent
9d23a98157
commit
7536645eea
26 changed files with 496 additions and 519 deletions
|
@ -1177,7 +1177,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn editor_blocks(editor: &ViewHandle<Editor>, cx: &mut AppContext) -> Vec<(u32, String)> {
|
fn editor_blocks(editor: &ViewHandle<Editor>, cx: &mut AppContext) -> Vec<(u32, String)> {
|
||||||
let mut presenter = cx.build_presenter(editor.id(), 0., Default::default());
|
let mut presenter = cx.build_window(editor.id(), 0., Default::default());
|
||||||
let mut cx = presenter.build_layout_context(Default::default(), false, cx);
|
let mut cx = presenter.build_layout_context(Default::default(), false, cx);
|
||||||
cx.render(editor, |editor, cx| {
|
cx.render(editor, |editor, cx| {
|
||||||
let snapshot = editor.snapshot(cx);
|
let snapshot = editor.snapshot(cx);
|
||||||
|
|
|
@ -2531,7 +2531,7 @@ mod tests {
|
||||||
|
|
||||||
let layouts = editor.update(cx, |editor, cx| {
|
let layouts = editor.update(cx, |editor, cx| {
|
||||||
let snapshot = editor.snapshot(cx);
|
let snapshot = editor.snapshot(cx);
|
||||||
let mut presenter = cx.build_presenter(window_id, 30., Default::default());
|
let mut presenter = cx.build_window(window_id, 30., Default::default());
|
||||||
let layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx);
|
let layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx);
|
||||||
element
|
element
|
||||||
.layout_line_numbers(0..6, &Default::default(), false, &snapshot, &layout_cx)
|
.layout_line_numbers(0..6, &Default::default(), false, &snapshot, &layout_cx)
|
||||||
|
@ -2568,7 +2568,7 @@ mod tests {
|
||||||
let mut element = EditorElement::new(editor.downgrade(), editor.read(cx).style(cx));
|
let mut element = EditorElement::new(editor.downgrade(), editor.read(cx).style(cx));
|
||||||
|
|
||||||
let mut scene = SceneBuilder::new(1.0);
|
let mut scene = SceneBuilder::new(1.0);
|
||||||
let mut presenter = cx.build_presenter(window_id, 30., Default::default());
|
let mut presenter = cx.build_window(window_id, 30., Default::default());
|
||||||
let mut layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx);
|
let mut layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx);
|
||||||
let (size, mut state) = element.layout(
|
let (size, mut state) = element.layout(
|
||||||
SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)),
|
SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)),
|
||||||
|
|
|
@ -4,6 +4,7 @@ mod menu;
|
||||||
pub(crate) mod ref_counts;
|
pub(crate) mod ref_counts;
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub mod test_app_context;
|
pub mod test_app_context;
|
||||||
|
pub(crate) mod window;
|
||||||
mod window_input_handler;
|
mod window_input_handler;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -23,7 +24,6 @@ use std::{
|
||||||
|
|
||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use pathfinder_geometry::vector::Vector2F;
|
|
||||||
use postage::oneshot;
|
use postage::oneshot;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use smol::prelude::*;
|
use smol::prelude::*;
|
||||||
|
@ -48,8 +48,8 @@ use crate::{
|
||||||
self, Appearance, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton,
|
self, Appearance, KeyDownEvent, KeyUpEvent, ModifiersChangedEvent, MouseButton,
|
||||||
PathPromptOptions, Platform, PromptLevel, WindowBounds, WindowOptions,
|
PathPromptOptions, Platform, PromptLevel, WindowBounds, WindowOptions,
|
||||||
},
|
},
|
||||||
presenter::Presenter,
|
|
||||||
util::post_inc,
|
util::post_inc,
|
||||||
|
window::{Window, WindowContext},
|
||||||
AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId, TextLayoutCache,
|
AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId, TextLayoutCache,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1622,25 +1622,10 @@ impl AppContext {
|
||||||
let platform_window =
|
let platform_window =
|
||||||
this.platform
|
this.platform
|
||||||
.open_window(window_id, window_options, this.foreground.clone());
|
.open_window(window_id, window_options, this.foreground.clone());
|
||||||
let presenter = self.build_presenter(
|
let window =
|
||||||
window_id,
|
this.build_window(window_id, root_view.clone().into_any(), platform_window);
|
||||||
platform_window.titlebar_height(),
|
|
||||||
platform_window.appearance(),
|
|
||||||
);
|
|
||||||
this.register_platform_window(window_id, &mut presenter, platform_window.as_mut());
|
|
||||||
|
|
||||||
this.windows.insert(
|
this.windows.insert(window_id, window);
|
||||||
window_id,
|
|
||||||
Window {
|
|
||||||
root_view: root_view.clone().into_any(),
|
|
||||||
focused_view_id: Some(root_view.id()),
|
|
||||||
is_active: false,
|
|
||||||
invalidation: None,
|
|
||||||
is_fullscreen: false,
|
|
||||||
platform_window,
|
|
||||||
presenter,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
|
root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
|
||||||
|
|
||||||
(window_id, root_view)
|
(window_id, root_view)
|
||||||
|
@ -1658,27 +1643,11 @@ impl AppContext {
|
||||||
.build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
|
.build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut platform_window = this.platform.add_status_item();
|
let platform_window = this.platform.add_status_item();
|
||||||
let mut presenter = self.build_presenter(
|
let window =
|
||||||
window_id,
|
this.build_window(window_id, root_view.clone().into_any(), platform_window);
|
||||||
platform_window.titlebar_height(),
|
|
||||||
platform_window.appearance(),
|
|
||||||
);
|
|
||||||
this.register_platform_window(window_id, &mut presenter, platform_window.as_mut());
|
|
||||||
|
|
||||||
let focused_view_id = root_view.id();
|
this.windows.insert(window_id, window);
|
||||||
this.windows.insert(
|
|
||||||
window_id,
|
|
||||||
Window {
|
|
||||||
root_view: root_view.clone().into_any(),
|
|
||||||
focused_view_id: Some(focused_view_id),
|
|
||||||
is_active: false,
|
|
||||||
invalidation: None,
|
|
||||||
is_fullscreen: false,
|
|
||||||
platform_window,
|
|
||||||
presenter,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
|
root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
|
||||||
|
|
||||||
(window_id, root_view)
|
(window_id, root_view)
|
||||||
|
@ -1689,12 +1658,33 @@ impl AppContext {
|
||||||
self.remove_window(id);
|
self.remove_window(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_platform_window(
|
pub fn replace_root_view<T, F>(&mut self, window_id: usize, build_root_view: F) -> ViewHandle<T>
|
||||||
|
where
|
||||||
|
T: View,
|
||||||
|
F: FnOnce(&mut ViewContext<T>) -> T,
|
||||||
|
{
|
||||||
|
self.update(|this| {
|
||||||
|
let root_view = this
|
||||||
|
.build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
|
||||||
|
.unwrap();
|
||||||
|
let window = this.windows.get_mut(&window_id).unwrap();
|
||||||
|
window.root_view = root_view.clone().into_any();
|
||||||
|
window.focused_view_id = Some(root_view.id());
|
||||||
|
root_view
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_window(&mut self, window_id: usize) {
|
||||||
|
self.windows.remove(&window_id);
|
||||||
|
self.flush_effects();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_window(
|
||||||
&mut self,
|
&mut self,
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
presenter: &mut Presenter,
|
root_view: AnyViewHandle,
|
||||||
platform_window: &mut dyn platform::Window,
|
mut platform_window: Box<dyn platform::Window>,
|
||||||
) {
|
) -> Window {
|
||||||
{
|
{
|
||||||
let mut app = self.upgrade();
|
let mut app = self.upgrade();
|
||||||
|
|
||||||
|
@ -1758,51 +1748,19 @@ impl AppContext {
|
||||||
window_id,
|
window_id,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let scene = presenter.build_scene(
|
let mut window = Window::new(
|
||||||
platform_window.content_size(),
|
|
||||||
platform_window.scale_factor(),
|
|
||||||
false,
|
|
||||||
self,
|
|
||||||
);
|
|
||||||
platform_window.present_scene(scene);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn replace_root_view<T, F>(&mut self, window_id: usize, build_root_view: F) -> ViewHandle<T>
|
|
||||||
where
|
|
||||||
T: View,
|
|
||||||
F: FnOnce(&mut ViewContext<T>) -> T,
|
|
||||||
{
|
|
||||||
self.update(|this| {
|
|
||||||
let root_view = this
|
|
||||||
.build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
|
|
||||||
.unwrap();
|
|
||||||
let window = this.windows.get_mut(&window_id).unwrap();
|
|
||||||
window.root_view = root_view.clone().into_any();
|
|
||||||
window.focused_view_id = Some(root_view.id());
|
|
||||||
root_view
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_window(&mut self, window_id: usize) {
|
|
||||||
self.windows.remove(&window_id);
|
|
||||||
self.flush_effects();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_presenter(
|
|
||||||
&mut self,
|
|
||||||
window_id: usize,
|
|
||||||
titlebar_height: f32,
|
|
||||||
appearance: Appearance,
|
|
||||||
) -> Presenter {
|
|
||||||
Presenter::new(
|
|
||||||
window_id,
|
window_id,
|
||||||
titlebar_height,
|
root_view,
|
||||||
appearance,
|
platform_window,
|
||||||
self.font_cache.clone(),
|
self.font_cache.clone(),
|
||||||
TextLayoutCache::new(self.platform.fonts()),
|
TextLayoutCache::new(self.platform.fonts()),
|
||||||
self.assets.clone(),
|
self.assets.clone(),
|
||||||
self,
|
self,
|
||||||
)
|
);
|
||||||
|
|
||||||
|
let scene = WindowContext::new(self, &mut window, window_id).build_scene(false);
|
||||||
|
window.platform_window.present_scene(scene);
|
||||||
|
window
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_view<T, F>(&mut self, parent_handle: &AnyViewHandle, build_view: F) -> ViewHandle<T>
|
pub fn add_view<T, F>(&mut self, parent_handle: &AnyViewHandle, build_view: F) -> ViewHandle<T>
|
||||||
|
@ -2144,21 +2102,16 @@ impl AppContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_windows(&mut self) {
|
fn update_windows(&mut self) {
|
||||||
for (window_id, window) in &mut self.windows {
|
let window_ids = self.windows.keys().cloned().collect::<Vec<_>>();
|
||||||
if let Some(mut invalidation) = window.invalidation.take() {
|
for window_id in window_ids {
|
||||||
window.presenter.invalidate(
|
self.update_window(window_id, |cx| {
|
||||||
&mut invalidation,
|
if let Some(mut invalidation) = cx.window.invalidation.take() {
|
||||||
window.platform_window.appearance(),
|
let appearance = cx.window.platform_window.appearance();
|
||||||
self,
|
cx.invalidate(&mut invalidation, appearance);
|
||||||
);
|
let scene = cx.build_scene(false);
|
||||||
let scene = window.presenter.build_scene(
|
cx.window.platform_window.present_scene(scene);
|
||||||
window.platform_window.content_size(),
|
}
|
||||||
window.platform_window.scale_factor(),
|
});
|
||||||
false,
|
|
||||||
self,
|
|
||||||
);
|
|
||||||
window.platform_window.present_scene(scene);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2223,20 +2176,14 @@ impl AppContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn perform_window_refresh(&mut self) {
|
fn perform_window_refresh(&mut self) {
|
||||||
for window in self.windows.values_mut() {
|
let window_ids = self.windows.keys().cloned().collect::<Vec<_>>();
|
||||||
let mut invalidation = window.invalidation.take().unwrap_or_default();
|
for window_id in window_ids {
|
||||||
window.presenter.invalidate(
|
self.update_window(window_id, |cx| {
|
||||||
&mut invalidation,
|
let mut invalidation = cx.window.invalidation.take().unwrap_or_default();
|
||||||
window.platform_window.appearance(),
|
cx.invalidate(&mut invalidation, cx.window.platform_window.appearance());
|
||||||
self,
|
let scene = cx.build_scene(true);
|
||||||
);
|
cx.window.platform_window.present_scene(scene);
|
||||||
let scene = window.presenter.build_scene(
|
});
|
||||||
window.platform_window.content_size(),
|
|
||||||
window.platform_window.scale_factor(),
|
|
||||||
true,
|
|
||||||
self,
|
|
||||||
);
|
|
||||||
window.platform_window.present_scene(scene);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2478,14 +2425,12 @@ impl AppContext {
|
||||||
self.update_window(window_id, |cx| {
|
self.update_window(window_id, |cx| {
|
||||||
if let Some(display) = cx.window_display_uuid() {
|
if let Some(display) = cx.window_display_uuid() {
|
||||||
let bounds = cx.window_bounds();
|
let bounds = cx.window_bounds();
|
||||||
cx.window_bounds_observations.clone().emit(
|
cx.window_bounds_observations
|
||||||
window_id,
|
.clone()
|
||||||
self,
|
.emit(window_id, cx, move |callback, this| {
|
||||||
move |callback, this| {
|
|
||||||
callback(bounds, display, this);
|
callback(bounds, display, this);
|
||||||
true
|
true
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -2708,16 +2653,6 @@ pub enum ParentId {
|
||||||
Root,
|
Root,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window {
|
|
||||||
root_view: AnyViewHandle,
|
|
||||||
focused_view_id: Option<usize>,
|
|
||||||
is_active: bool,
|
|
||||||
is_fullscreen: bool,
|
|
||||||
invalidation: Option<WindowInvalidation>,
|
|
||||||
presenter: Presenter,
|
|
||||||
platform_window: Box<dyn platform::Window>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone)]
|
||||||
pub struct WindowInvalidation {
|
pub struct WindowInvalidation {
|
||||||
pub updated: HashSet<usize>,
|
pub updated: HashSet<usize>,
|
||||||
|
@ -3494,138 +3429,6 @@ impl<M> DerefMut for ModelContext<'_, M> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WindowContext<'a: 'b, 'b> {
|
|
||||||
app_context: &'a mut AppContext,
|
|
||||||
window: &'b mut Window,
|
|
||||||
window_id: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for WindowContext<'_, '_> {
|
|
||||||
type Target = AppContext;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.app_context
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for WindowContext<'_, '_> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.app_context
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WindowContext<'_, '_> {
|
|
||||||
pub fn dispatch_keystroke(&mut self, keystroke: &Keystroke) -> bool {
|
|
||||||
let window_id = self.window_id;
|
|
||||||
if let Some(focused_view_id) = self.focused_view_id(window_id) {
|
|
||||||
let dispatch_path = self
|
|
||||||
.ancestors(window_id, focused_view_id)
|
|
||||||
.filter_map(|view_id| {
|
|
||||||
self.views
|
|
||||||
.get(&(window_id, view_id))
|
|
||||||
.map(|view| (view_id, view.keymap_context(self)))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let match_result = self
|
|
||||||
.keystroke_matcher
|
|
||||||
.push_keystroke(keystroke.clone(), dispatch_path);
|
|
||||||
let mut handled_by = None;
|
|
||||||
|
|
||||||
let keystroke_handled = match &match_result {
|
|
||||||
MatchResult::None => false,
|
|
||||||
MatchResult::Pending => true,
|
|
||||||
MatchResult::Matches(matches) => {
|
|
||||||
for (view_id, action) in matches {
|
|
||||||
if self.handle_dispatch_action_from_effect(
|
|
||||||
window_id,
|
|
||||||
Some(*view_id),
|
|
||||||
action.as_ref(),
|
|
||||||
) {
|
|
||||||
self.keystroke_matcher.clear_pending();
|
|
||||||
handled_by = Some(action.boxed_clone());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
handled_by.is_some()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.keystroke(
|
|
||||||
window_id,
|
|
||||||
keystroke.clone(),
|
|
||||||
handled_by,
|
|
||||||
match_result.clone(),
|
|
||||||
);
|
|
||||||
keystroke_handled
|
|
||||||
} else {
|
|
||||||
self.keystroke(window_id, keystroke.clone(), None, MatchResult::None);
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dispatch_event(&mut self, event: Event, event_reused: bool) -> bool {
|
|
||||||
self.window
|
|
||||||
.presenter
|
|
||||||
.dispatch_event(event, event_reused, self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_window_title(&mut self, title: &str) {
|
|
||||||
self.window.platform_window.set_title(title);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_window_edited(&mut self, edited: bool) {
|
|
||||||
self.window.platform_window.set_edited(edited);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_topmost_window_for_position(&self, position: Vector2F) -> bool {
|
|
||||||
self.window
|
|
||||||
.platform_window
|
|
||||||
.is_topmost_for_position(position)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn activate_window(&self) {
|
|
||||||
self.window.platform_window.activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn window_bounds(&self) -> WindowBounds {
|
|
||||||
self.window.platform_window.bounds()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn window_display_uuid(&self) -> Option<Uuid> {
|
|
||||||
self.window.platform_window.screen().display_uuid()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn debug_elements(&self) -> Option<crate::json::Value> {
|
|
||||||
self.window.presenter.debug_elements(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show_character_palette(&self) {
|
|
||||||
self.window.platform_window.show_character_palette();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn minimize_window(&self) {
|
|
||||||
self.window.platform_window.minimize();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn zoom_window(&self) {
|
|
||||||
self.window.platform_window.zoom();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toggle_window_full_screen(&self) {
|
|
||||||
self.window.platform_window.toggle_full_screen();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn prompt(
|
|
||||||
&self,
|
|
||||||
level: PromptLevel,
|
|
||||||
msg: &str,
|
|
||||||
answers: &[&str],
|
|
||||||
) -> oneshot::Receiver<usize> {
|
|
||||||
self.window.platform_window.prompt(level, msg, answers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ViewContext<'a, T: ?Sized> {
|
pub struct ViewContext<'a, T: ?Sized> {
|
||||||
app: &'a mut AppContext,
|
app: &'a mut AppContext,
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
|
@ -5139,6 +4942,7 @@ mod tests {
|
||||||
elements::*,
|
elements::*,
|
||||||
impl_actions,
|
impl_actions,
|
||||||
platform::{MouseButton, MouseButtonEvent},
|
platform::{MouseButton, MouseButtonEvent},
|
||||||
|
window::ChildView,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use postage::{sink::Sink, stream::Stream};
|
use postage::{sink::Sink, stream::Stream};
|
||||||
|
@ -6847,7 +6651,7 @@ mod tests {
|
||||||
let (window_id, root_view) = cx.add_window(Default::default(), |_| View(0));
|
let (window_id, root_view) = cx.add_window(Default::default(), |_| View(0));
|
||||||
cx.update_window(window_id, |cx| {
|
cx.update_window(window_id, |cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.window.presenter.rendered_views[&root_view.id()].name(),
|
cx.window.rendered_views[&root_view.id()].name(),
|
||||||
Some("render count: 0")
|
Some("render count: 0")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -6859,11 +6663,11 @@ mod tests {
|
||||||
|
|
||||||
cx.update_window(window_id, |cx| {
|
cx.update_window(window_id, |cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.window.presenter.rendered_views[&root_view.id()].name(),
|
cx.window.rendered_views[&root_view.id()].name(),
|
||||||
Some("render count: 1")
|
Some("render count: 1")
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.window.presenter.rendered_views[&view.id()].name(),
|
cx.window.rendered_views[&view.id()].name(),
|
||||||
Some("render count: 0")
|
Some("render count: 0")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -6872,11 +6676,11 @@ mod tests {
|
||||||
|
|
||||||
cx.update_window(window_id, |cx| {
|
cx.update_window(window_id, |cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.window.presenter.rendered_views[&root_view.id()].name(),
|
cx.window.rendered_views[&root_view.id()].name(),
|
||||||
Some("render count: 2")
|
Some("render count: 2")
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.window.presenter.rendered_views[&view.id()].name(),
|
cx.window.rendered_views[&view.id()].name(),
|
||||||
Some("render count: 1")
|
Some("render count: 1")
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -6888,10 +6692,10 @@ mod tests {
|
||||||
|
|
||||||
cx.update_window(window_id, |cx| {
|
cx.update_window(window_id, |cx| {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cx.window.presenter.rendered_views[&root_view.id()].name(),
|
cx.window.rendered_views[&root_view.id()].name(),
|
||||||
Some("render count: 3")
|
Some("render count: 3")
|
||||||
);
|
);
|
||||||
assert_eq!(cx.window.presenter.rendered_views.len(), 1);
|
assert_eq!(cx.window.rendered_views.len(), 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,13 +92,12 @@ impl TestAppContext {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if cx.window.presenter.dispatch_event(
|
if cx.dispatch_event(
|
||||||
Event::KeyDown(KeyDownEvent {
|
Event::KeyDown(KeyDownEvent {
|
||||||
keystroke: keystroke.clone(),
|
keystroke: keystroke.clone(),
|
||||||
is_held,
|
is_held,
|
||||||
}),
|
}),
|
||||||
false,
|
false,
|
||||||
cx,
|
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -286,12 +285,15 @@ impl TestAppContext {
|
||||||
|
|
||||||
pub fn simulate_window_activation(&self, to_activate: Option<usize>) {
|
pub fn simulate_window_activation(&self, to_activate: Option<usize>) {
|
||||||
self.cx.borrow_mut().update(|cx| {
|
self.cx.borrow_mut().update(|cx| {
|
||||||
for window_id in cx
|
let other_window_ids = cx
|
||||||
.windows
|
.windows
|
||||||
.keys()
|
.keys()
|
||||||
.filter(|window_id| Some(**window_id) != to_activate)
|
.filter(|window_id| Some(**window_id) != to_activate)
|
||||||
{
|
.copied()
|
||||||
cx.window_changed_active_status(*window_id, false)
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for window_id in other_window_ids {
|
||||||
|
cx.window_changed_active_status(window_id, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(to_activate) = to_activate {
|
if let Some(to_activate) = to_activate {
|
||||||
|
|
|
@ -4,7 +4,11 @@ use crate::{
|
||||||
font_cache::FontCache,
|
font_cache::FontCache,
|
||||||
geometry::rect::RectF,
|
geometry::rect::RectF,
|
||||||
json::{self, ToJson},
|
json::{self, ToJson},
|
||||||
platform::{Appearance, CursorStyle, Event, FontSystem, MouseButton, MouseMovedEvent},
|
keymap_matcher::{Keystroke, MatchResult},
|
||||||
|
platform::{
|
||||||
|
self, Appearance, CursorStyle, Event, FontSystem, MouseButton, MouseMovedEvent,
|
||||||
|
PromptLevel, WindowBounds,
|
||||||
|
},
|
||||||
scene::{
|
scene::{
|
||||||
CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover,
|
CursorRegion, MouseClick, MouseDown, MouseDownOut, MouseDrag, MouseEvent, MouseHover,
|
||||||
MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
|
MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
|
||||||
|
@ -18,6 +22,7 @@ use crate::{
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||||
|
use postage::oneshot;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use sqlez::{
|
use sqlez::{
|
||||||
|
@ -29,9 +34,16 @@ use std::{
|
||||||
ops::{Deref, DerefMut, Range},
|
ops::{Deref, DerefMut, Range},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
pub struct Presenter {
|
pub struct Window {
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
|
pub(crate) root_view: AnyViewHandle,
|
||||||
|
pub(crate) focused_view_id: Option<usize>,
|
||||||
|
pub(crate) is_active: bool,
|
||||||
|
pub(crate) is_fullscreen: bool,
|
||||||
|
pub(crate) invalidation: Option<WindowInvalidation>,
|
||||||
|
pub(crate) platform_window: Box<dyn platform::Window>,
|
||||||
pub(crate) rendered_views: HashMap<usize, ElementBox>,
|
pub(crate) rendered_views: HashMap<usize, ElementBox>,
|
||||||
cursor_regions: Vec<CursorRegion>,
|
cursor_regions: Vec<CursorRegion>,
|
||||||
mouse_regions: Vec<(MouseRegion, usize)>,
|
mouse_regions: Vec<(MouseRegion, usize)>,
|
||||||
|
@ -47,18 +59,27 @@ pub struct Presenter {
|
||||||
appearance: Appearance,
|
appearance: Appearance,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Presenter {
|
impl Window {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
window_id: usize,
|
window_id: usize,
|
||||||
titlebar_height: f32,
|
root_view: AnyViewHandle,
|
||||||
appearance: Appearance,
|
platform_window: Box<dyn platform::Window>,
|
||||||
font_cache: Arc<FontCache>,
|
font_cache: Arc<FontCache>,
|
||||||
text_layout_cache: TextLayoutCache,
|
text_layout_cache: TextLayoutCache,
|
||||||
asset_cache: Arc<AssetCache>,
|
asset_cache: Arc<AssetCache>,
|
||||||
cx: &mut AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let focused_view_id = Some(root_view.id());
|
||||||
|
let titlebar_height = platform_window.titlebar_height();
|
||||||
|
let appearance = platform_window.appearance();
|
||||||
Self {
|
Self {
|
||||||
window_id,
|
window_id,
|
||||||
|
root_view,
|
||||||
|
focused_view_id,
|
||||||
|
is_active: false,
|
||||||
|
invalidation: None,
|
||||||
|
is_fullscreen: false,
|
||||||
|
platform_window,
|
||||||
rendered_views: cx.render_views(window_id, titlebar_height, appearance),
|
rendered_views: cx.render_views(window_id, titlebar_height, appearance),
|
||||||
cursor_regions: Default::default(),
|
cursor_regions: Default::default(),
|
||||||
mouse_regions: Default::default(),
|
mouse_regions: Default::default(),
|
||||||
|
@ -74,180 +95,101 @@ impl Presenter {
|
||||||
appearance,
|
appearance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn invalidate(
|
pub struct WindowContext<'a: 'b, 'b> {
|
||||||
&mut self,
|
app_context: &'a mut AppContext,
|
||||||
invalidation: &mut WindowInvalidation,
|
pub(crate) window: &'b mut Window, // TODO: make this private?
|
||||||
appearance: Appearance,
|
window_id: usize,
|
||||||
cx: &mut AppContext,
|
}
|
||||||
) {
|
|
||||||
cx.start_frame();
|
impl Deref for WindowContext<'_, '_> {
|
||||||
self.appearance = appearance;
|
type Target = AppContext;
|
||||||
for view_id in &invalidation.removed {
|
|
||||||
invalidation.updated.remove(view_id);
|
fn deref(&self) -> &Self::Target {
|
||||||
self.rendered_views.remove(view_id);
|
self.app_context
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for WindowContext<'_, '_> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.app_context
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a: 'b, 'b> WindowContext<'a, 'b> {
|
||||||
|
pub fn new(app_context: &'a mut AppContext, window: &'b mut Window, window_id: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
app_context,
|
||||||
|
window,
|
||||||
|
window_id,
|
||||||
}
|
}
|
||||||
for view_id in &invalidation.updated {
|
}
|
||||||
self.rendered_views.insert(
|
|
||||||
*view_id,
|
pub fn dispatch_keystroke(&mut self, keystroke: &Keystroke) -> bool {
|
||||||
cx.render_view(RenderParams {
|
let window_id = self.window_id;
|
||||||
window_id: self.window_id,
|
if let Some(focused_view_id) = self.focused_view_id(window_id) {
|
||||||
view_id: *view_id,
|
let dispatch_path = self
|
||||||
titlebar_height: self.titlebar_height,
|
.ancestors(window_id, focused_view_id)
|
||||||
hovered_region_ids: self.hovered_region_ids.clone(),
|
.filter_map(|view_id| {
|
||||||
clicked_region_ids: self
|
self.views
|
||||||
.clicked_button
|
.get(&(window_id, view_id))
|
||||||
.map(|button| (self.clicked_region_ids.clone(), button)),
|
.map(|view| (view_id, view.keymap_context(self)))
|
||||||
refreshing: false,
|
|
||||||
appearance,
|
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.collect();
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn refresh(
|
let match_result = self
|
||||||
&mut self,
|
.keystroke_matcher
|
||||||
invalidation: &mut WindowInvalidation,
|
.push_keystroke(keystroke.clone(), dispatch_path);
|
||||||
appearance: Appearance,
|
let mut handled_by = None;
|
||||||
cx: &mut AppContext,
|
|
||||||
) {
|
|
||||||
self.invalidate(invalidation, appearance, cx);
|
|
||||||
for (view_id, view) in &mut self.rendered_views {
|
|
||||||
if !invalidation.updated.contains(view_id) {
|
|
||||||
*view = cx
|
|
||||||
.render_view(RenderParams {
|
|
||||||
window_id: self.window_id,
|
|
||||||
view_id: *view_id,
|
|
||||||
titlebar_height: self.titlebar_height,
|
|
||||||
hovered_region_ids: self.hovered_region_ids.clone(),
|
|
||||||
clicked_region_ids: self
|
|
||||||
.clicked_button
|
|
||||||
.map(|button| (self.clicked_region_ids.clone(), button)),
|
|
||||||
refreshing: true,
|
|
||||||
appearance,
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_scene(
|
let keystroke_handled = match &match_result {
|
||||||
&mut self,
|
MatchResult::None => false,
|
||||||
window_size: Vector2F,
|
MatchResult::Pending => true,
|
||||||
scale_factor: f32,
|
MatchResult::Matches(matches) => {
|
||||||
refreshing: bool,
|
for (view_id, action) in matches {
|
||||||
cx: &mut AppContext,
|
if self.handle_dispatch_action_from_effect(
|
||||||
) -> Scene {
|
window_id,
|
||||||
let mut scene_builder = SceneBuilder::new(scale_factor);
|
Some(*view_id),
|
||||||
|
action.as_ref(),
|
||||||
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
|
) {
|
||||||
self.layout(window_size, refreshing, cx);
|
self.keystroke_matcher.clear_pending();
|
||||||
let mut paint_cx = self.build_paint_context(&mut scene_builder, window_size, cx);
|
handled_by = Some(action.boxed_clone());
|
||||||
paint_cx.paint(
|
break;
|
||||||
root_view_id,
|
}
|
||||||
Vector2F::zero(),
|
}
|
||||||
RectF::new(Vector2F::zero(), window_size),
|
handled_by.is_some()
|
||||||
);
|
|
||||||
self.text_layout_cache.finish_frame();
|
|
||||||
let scene = scene_builder.build();
|
|
||||||
self.cursor_regions = scene.cursor_regions();
|
|
||||||
self.mouse_regions = scene.mouse_regions();
|
|
||||||
|
|
||||||
// window.is_topmost for the mouse moved event's postion?
|
|
||||||
if cx.window_is_active(self.window_id) {
|
|
||||||
if let Some(event) = self.last_mouse_moved_event.clone() {
|
|
||||||
self.dispatch_event(event, true, cx);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
scene
|
|
||||||
} else {
|
|
||||||
log::error!("could not find root_view_id for window {}", self.window_id);
|
|
||||||
scene_builder.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut AppContext) {
|
|
||||||
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
|
|
||||||
self.build_layout_context(window_size, refreshing, cx)
|
|
||||||
.layout(root_view_id, SizeConstraint::strict(window_size));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_layout_context<'a>(
|
|
||||||
&'a mut self,
|
|
||||||
window_size: Vector2F,
|
|
||||||
refreshing: bool,
|
|
||||||
cx: &'a mut AppContext,
|
|
||||||
) -> LayoutContext<'a> {
|
|
||||||
LayoutContext {
|
|
||||||
window_id: self.window_id,
|
|
||||||
rendered_views: &mut self.rendered_views,
|
|
||||||
font_cache: &self.font_cache,
|
|
||||||
font_system: cx.platform().fonts(),
|
|
||||||
text_layout_cache: &self.text_layout_cache,
|
|
||||||
asset_cache: &self.asset_cache,
|
|
||||||
view_stack: Vec::new(),
|
|
||||||
refreshing,
|
|
||||||
hovered_region_ids: self.hovered_region_ids.clone(),
|
|
||||||
clicked_region_ids: self
|
|
||||||
.clicked_button
|
|
||||||
.map(|button| (self.clicked_region_ids.clone(), button)),
|
|
||||||
titlebar_height: self.titlebar_height,
|
|
||||||
appearance: self.appearance,
|
|
||||||
window_size,
|
|
||||||
app: cx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn build_paint_context<'a>(
|
|
||||||
&'a mut self,
|
|
||||||
scene: &'a mut SceneBuilder,
|
|
||||||
window_size: Vector2F,
|
|
||||||
cx: &'a mut AppContext,
|
|
||||||
) -> PaintContext {
|
|
||||||
PaintContext {
|
|
||||||
scene,
|
|
||||||
window_size,
|
|
||||||
font_cache: &self.font_cache,
|
|
||||||
text_layout_cache: &self.text_layout_cache,
|
|
||||||
rendered_views: &mut self.rendered_views,
|
|
||||||
view_stack: Vec::new(),
|
|
||||||
app: cx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rect_for_text_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<RectF> {
|
|
||||||
cx.focused_view_id(self.window_id).and_then(|view_id| {
|
|
||||||
let cx = MeasurementContext {
|
|
||||||
app: cx,
|
|
||||||
rendered_views: &self.rendered_views,
|
|
||||||
window_id: self.window_id,
|
|
||||||
};
|
};
|
||||||
cx.rect_for_text_range(view_id, range_utf16)
|
|
||||||
})
|
self.keystroke(
|
||||||
|
window_id,
|
||||||
|
keystroke.clone(),
|
||||||
|
handled_by,
|
||||||
|
match_result.clone(),
|
||||||
|
);
|
||||||
|
keystroke_handled
|
||||||
|
} else {
|
||||||
|
self.keystroke(window_id, keystroke.clone(), None, MatchResult::None);
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dispatch_event(
|
pub fn dispatch_event(&mut self, event: Event, event_reused: bool) -> bool {
|
||||||
&mut self,
|
|
||||||
event: Event,
|
|
||||||
event_reused: bool,
|
|
||||||
cx: &mut AppContext,
|
|
||||||
) -> bool {
|
|
||||||
let mut mouse_events = SmallVec::<[_; 2]>::new();
|
let mut mouse_events = SmallVec::<[_; 2]>::new();
|
||||||
let mut notified_views: HashSet<usize> = Default::default();
|
let mut notified_views: HashSet<usize> = Default::default();
|
||||||
|
let window_id = self.window_id;
|
||||||
|
|
||||||
// 1. Handle platform event. Keyboard events get dispatched immediately, while mouse events
|
// 1. Handle platform event. Keyboard events get dispatched immediately, while mouse events
|
||||||
// get mapped into the mouse-specific MouseEvent type.
|
// get mapped into the mouse-specific MouseEvent type.
|
||||||
// -> These are usually small: [Mouse Down] or [Mouse up, Click] or [Mouse Moved, Mouse Dragged?]
|
// -> These are usually small: [Mouse Down] or [Mouse up, Click] or [Mouse Moved, Mouse Dragged?]
|
||||||
// -> Also updates mouse-related state
|
// -> Also updates mouse-related state
|
||||||
match &event {
|
match &event {
|
||||||
Event::KeyDown(e) => return cx.dispatch_key_down(self.window_id, e),
|
Event::KeyDown(e) => return self.dispatch_key_down(window_id, e),
|
||||||
|
|
||||||
Event::KeyUp(e) => return cx.dispatch_key_up(self.window_id, e),
|
Event::KeyUp(e) => return self.dispatch_key_up(window_id, e),
|
||||||
|
|
||||||
Event::ModifiersChanged(e) => return cx.dispatch_modifiers_changed(self.window_id, e),
|
Event::ModifiersChanged(e) => return self.dispatch_modifiers_changed(window_id, e),
|
||||||
|
|
||||||
Event::MouseDown(e) => {
|
Event::MouseDown(e) => {
|
||||||
// Click events are weird because they can be fired after a drag event.
|
// Click events are weird because they can be fired after a drag event.
|
||||||
|
@ -256,8 +198,9 @@ impl Presenter {
|
||||||
// So we need to store the overlapping regions on mouse down.
|
// So we need to store the overlapping regions on mouse down.
|
||||||
|
|
||||||
// If there is already clicked_button stored, don't replace it.
|
// If there is already clicked_button stored, don't replace it.
|
||||||
if self.clicked_button.is_none() {
|
if self.window.clicked_button.is_none() {
|
||||||
self.clicked_region_ids = self
|
self.window.clicked_region_ids = self
|
||||||
|
.window
|
||||||
.mouse_regions
|
.mouse_regions
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(region, _)| {
|
.filter_map(|(region, _)| {
|
||||||
|
@ -269,7 +212,7 @@ impl Presenter {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
self.clicked_button = Some(e.button);
|
self.window.clicked_button = Some(e.button);
|
||||||
}
|
}
|
||||||
|
|
||||||
mouse_events.push(MouseEvent::Down(MouseDown {
|
mouse_events.push(MouseEvent::Down(MouseDown {
|
||||||
|
@ -308,26 +251,29 @@ impl Presenter {
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
let mut style_to_assign = CursorStyle::Arrow;
|
let mut style_to_assign = CursorStyle::Arrow;
|
||||||
for region in self.cursor_regions.iter().rev() {
|
for region in self.window.cursor_regions.iter().rev() {
|
||||||
if region.bounds.contains_point(*position) {
|
if region.bounds.contains_point(*position) {
|
||||||
style_to_assign = region.style;
|
style_to_assign = region.style;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
if self
|
||||||
// if cx.is_topmost_window_for_position(self.window_id, *position) {
|
.window
|
||||||
// cx.platform().set_cursor_style(style_to_assign);
|
.platform_window
|
||||||
// }
|
.is_topmost_for_position(*position)
|
||||||
|
{
|
||||||
|
self.platform().set_cursor_style(style_to_assign);
|
||||||
|
}
|
||||||
|
|
||||||
if !event_reused {
|
if !event_reused {
|
||||||
if pressed_button.is_some() {
|
if pressed_button.is_some() {
|
||||||
mouse_events.push(MouseEvent::Drag(MouseDrag {
|
mouse_events.push(MouseEvent::Drag(MouseDrag {
|
||||||
region: Default::default(),
|
region: Default::default(),
|
||||||
prev_mouse_position: self.mouse_position,
|
prev_mouse_position: self.window.mouse_position,
|
||||||
platform_event: e.clone(),
|
platform_event: e.clone(),
|
||||||
}));
|
}));
|
||||||
} else if let Some(clicked_button) = self.clicked_button {
|
} else if let Some(clicked_button) = self.window.clicked_button {
|
||||||
// Mouse up event happened outside the current window. Simulate mouse up button event
|
// Mouse up event happened outside the current window. Simulate mouse up button event
|
||||||
let button_event = e.to_button_event(clicked_button);
|
let button_event = e.to_button_event(clicked_button);
|
||||||
mouse_events.push(MouseEvent::Up(MouseUp {
|
mouse_events.push(MouseEvent::Up(MouseUp {
|
||||||
|
@ -359,7 +305,7 @@ impl Presenter {
|
||||||
region: Default::default(),
|
region: Default::default(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
self.last_mouse_moved_event = Some(event.clone());
|
self.window.last_mouse_moved_event = Some(event.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
Event::MouseExited(event) => {
|
Event::MouseExited(event) => {
|
||||||
|
@ -373,7 +319,6 @@ impl Presenter {
|
||||||
modifiers: event.modifiers,
|
modifiers: event.modifiers,
|
||||||
}),
|
}),
|
||||||
event_reused,
|
event_reused,
|
||||||
cx,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +329,7 @@ impl Presenter {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(position) = event.position() {
|
if let Some(position) = event.position() {
|
||||||
self.mouse_position = position;
|
self.window.mouse_position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Dispatch mouse events on regions
|
// 2. Dispatch mouse events on regions
|
||||||
|
@ -398,8 +343,8 @@ impl Presenter {
|
||||||
match &mouse_event {
|
match &mouse_event {
|
||||||
MouseEvent::Hover(_) => {
|
MouseEvent::Hover(_) => {
|
||||||
let mut highest_z_index = None;
|
let mut highest_z_index = None;
|
||||||
let mouse_position = self.mouse_position.clone();
|
let mouse_position = self.window.mouse_position.clone();
|
||||||
for (region, z_index) in self.mouse_regions.iter().rev() {
|
for (region, z_index) in self.window.mouse_regions.iter().rev() {
|
||||||
// Allow mouse regions to appear transparent to hovers
|
// Allow mouse regions to appear transparent to hovers
|
||||||
if !region.hoverable {
|
if !region.hoverable {
|
||||||
continue;
|
continue;
|
||||||
|
@ -417,7 +362,7 @@ impl Presenter {
|
||||||
// highest_z_index is set.
|
// highest_z_index is set.
|
||||||
if contains_mouse && z_index == highest_z_index.unwrap() {
|
if contains_mouse && z_index == highest_z_index.unwrap() {
|
||||||
//Ensure that hover entrance events aren't sent twice
|
//Ensure that hover entrance events aren't sent twice
|
||||||
if self.hovered_region_ids.insert(region.id()) {
|
if self.window.hovered_region_ids.insert(region.id()) {
|
||||||
valid_regions.push(region.clone());
|
valid_regions.push(region.clone());
|
||||||
if region.notify_on_hover {
|
if region.notify_on_hover {
|
||||||
notified_views.insert(region.id().view_id());
|
notified_views.insert(region.id().view_id());
|
||||||
|
@ -425,7 +370,7 @@ impl Presenter {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Ensure that hover exit events aren't sent twice
|
// Ensure that hover exit events aren't sent twice
|
||||||
if self.hovered_region_ids.remove(®ion.id()) {
|
if self.window.hovered_region_ids.remove(®ion.id()) {
|
||||||
valid_regions.push(region.clone());
|
valid_regions.push(region.clone());
|
||||||
if region.notify_on_hover {
|
if region.notify_on_hover {
|
||||||
notified_views.insert(region.id().view_id());
|
notified_views.insert(region.id().view_id());
|
||||||
|
@ -436,8 +381,8 @@ impl Presenter {
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseEvent::Down(_) | MouseEvent::Up(_) => {
|
MouseEvent::Down(_) | MouseEvent::Up(_) => {
|
||||||
for (region, _) in self.mouse_regions.iter().rev() {
|
for (region, _) in self.window.mouse_regions.iter().rev() {
|
||||||
if region.bounds.contains_point(self.mouse_position) {
|
if region.bounds.contains_point(self.window.mouse_position) {
|
||||||
valid_regions.push(region.clone());
|
valid_regions.push(region.clone());
|
||||||
if region.notify_on_click {
|
if region.notify_on_click {
|
||||||
notified_views.insert(region.id().view_id());
|
notified_views.insert(region.id().view_id());
|
||||||
|
@ -449,19 +394,25 @@ impl Presenter {
|
||||||
MouseEvent::Click(e) => {
|
MouseEvent::Click(e) => {
|
||||||
// Only raise click events if the released button is the same as the one stored
|
// Only raise click events if the released button is the same as the one stored
|
||||||
if self
|
if self
|
||||||
|
.window
|
||||||
.clicked_button
|
.clicked_button
|
||||||
.map(|clicked_button| clicked_button == e.button)
|
.map(|clicked_button| clicked_button == e.button)
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
// Clear clicked regions and clicked button
|
// Clear clicked regions and clicked button
|
||||||
let clicked_region_ids =
|
let clicked_region_ids = std::mem::replace(
|
||||||
std::mem::replace(&mut self.clicked_region_ids, Default::default());
|
&mut self.window.clicked_region_ids,
|
||||||
self.clicked_button = None;
|
Default::default(),
|
||||||
|
);
|
||||||
|
self.window.clicked_button = None;
|
||||||
|
|
||||||
// Find regions which still overlap with the mouse since the last MouseDown happened
|
// Find regions which still overlap with the mouse since the last MouseDown happened
|
||||||
for (mouse_region, _) in self.mouse_regions.iter().rev() {
|
for (mouse_region, _) in self.window.mouse_regions.iter().rev() {
|
||||||
if clicked_region_ids.contains(&mouse_region.id()) {
|
if clicked_region_ids.contains(&mouse_region.id()) {
|
||||||
if mouse_region.bounds.contains_point(self.mouse_position) {
|
if mouse_region
|
||||||
|
.bounds
|
||||||
|
.contains_point(self.window.mouse_position)
|
||||||
|
{
|
||||||
valid_regions.push(mouse_region.clone());
|
valid_regions.push(mouse_region.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -470,26 +421,32 @@ impl Presenter {
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseEvent::Drag(_) => {
|
MouseEvent::Drag(_) => {
|
||||||
for (mouse_region, _) in self.mouse_regions.iter().rev() {
|
for (mouse_region, _) in self.window.mouse_regions.iter().rev() {
|
||||||
if self.clicked_region_ids.contains(&mouse_region.id()) {
|
if self.window.clicked_region_ids.contains(&mouse_region.id()) {
|
||||||
valid_regions.push(mouse_region.clone());
|
valid_regions.push(mouse_region.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseEvent::MoveOut(_) | MouseEvent::UpOut(_) | MouseEvent::DownOut(_) => {
|
MouseEvent::MoveOut(_) | MouseEvent::UpOut(_) | MouseEvent::DownOut(_) => {
|
||||||
for (mouse_region, _) in self.mouse_regions.iter().rev() {
|
for (mouse_region, _) in self.window.mouse_regions.iter().rev() {
|
||||||
// NOT contains
|
// NOT contains
|
||||||
if !mouse_region.bounds.contains_point(self.mouse_position) {
|
if !mouse_region
|
||||||
|
.bounds
|
||||||
|
.contains_point(self.window.mouse_position)
|
||||||
|
{
|
||||||
valid_regions.push(mouse_region.clone());
|
valid_regions.push(mouse_region.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
for (mouse_region, _) in self.mouse_regions.iter().rev() {
|
for (mouse_region, _) in self.window.mouse_regions.iter().rev() {
|
||||||
// Contains
|
// Contains
|
||||||
if mouse_region.bounds.contains_point(self.mouse_position) {
|
if mouse_region
|
||||||
|
.bounds
|
||||||
|
.contains_point(self.window.mouse_position)
|
||||||
|
{
|
||||||
valid_regions.push(mouse_region.clone());
|
valid_regions.push(mouse_region.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -497,9 +454,9 @@ impl Presenter {
|
||||||
}
|
}
|
||||||
|
|
||||||
//3. Fire region events
|
//3. Fire region events
|
||||||
let hovered_region_ids = self.hovered_region_ids.clone();
|
let hovered_region_ids = self.window.hovered_region_ids.clone();
|
||||||
for valid_region in valid_regions.into_iter() {
|
for valid_region in valid_regions.into_iter() {
|
||||||
let mut event_cx = self.build_event_context(&mut notified_views, cx);
|
let mut event_cx = self.build_event_context(&mut notified_views);
|
||||||
|
|
||||||
mouse_event.set_region(valid_region.bounds);
|
mouse_event.set_region(valid_region.bounds);
|
||||||
if let MouseEvent::Hover(e) = &mut mouse_event {
|
if let MouseEvent::Hover(e) = &mut mouse_event {
|
||||||
|
@ -548,43 +505,253 @@ impl Presenter {
|
||||||
}
|
}
|
||||||
|
|
||||||
for view_id in notified_views {
|
for view_id in notified_views {
|
||||||
cx.notify_view(self.window_id, view_id);
|
self.notify_view(window_id, view_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
any_event_handled
|
any_event_handled
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_event_context<'a>(
|
pub fn build_event_context<'c>(
|
||||||
&'a mut self,
|
&'c mut self,
|
||||||
notified_views: &'a mut HashSet<usize>,
|
notified_views: &'c mut HashSet<usize>,
|
||||||
cx: &'a mut AppContext,
|
) -> EventContext<'c> {
|
||||||
) -> EventContext<'a> {
|
|
||||||
EventContext {
|
EventContext {
|
||||||
font_cache: &self.font_cache,
|
font_cache: &self.window.font_cache,
|
||||||
text_layout_cache: &self.text_layout_cache,
|
text_layout_cache: &self.window.text_layout_cache,
|
||||||
view_stack: Default::default(),
|
view_stack: Default::default(),
|
||||||
notified_views,
|
notified_views,
|
||||||
notify_count: 0,
|
notify_count: 0,
|
||||||
handled: false,
|
handled: false,
|
||||||
window_id: self.window_id,
|
window_id: self.window_id,
|
||||||
|
app: self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invalidate(&mut self, invalidation: &mut WindowInvalidation, appearance: Appearance) {
|
||||||
|
self.start_frame();
|
||||||
|
self.window.appearance = appearance;
|
||||||
|
for view_id in &invalidation.removed {
|
||||||
|
invalidation.updated.remove(view_id);
|
||||||
|
self.window.rendered_views.remove(view_id);
|
||||||
|
}
|
||||||
|
for view_id in &invalidation.updated {
|
||||||
|
let window_id = self.window_id;
|
||||||
|
let titlebar_height = self.window.titlebar_height;
|
||||||
|
let hovered_region_ids = self.window.hovered_region_ids.clone();
|
||||||
|
let clicked_region_ids = self
|
||||||
|
.window
|
||||||
|
.clicked_button
|
||||||
|
.map(|button| (self.window.clicked_region_ids.clone(), button));
|
||||||
|
|
||||||
|
let element = self
|
||||||
|
.render_view(RenderParams {
|
||||||
|
window_id,
|
||||||
|
view_id: *view_id,
|
||||||
|
titlebar_height,
|
||||||
|
hovered_region_ids,
|
||||||
|
clicked_region_ids,
|
||||||
|
refreshing: false,
|
||||||
|
appearance,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
self.window.rendered_views.insert(*view_id, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn refresh(&mut self, invalidation: &mut WindowInvalidation, appearance: Appearance) {
|
||||||
|
self.invalidate(invalidation, appearance);
|
||||||
|
|
||||||
|
let view_ids = self
|
||||||
|
.window
|
||||||
|
.rendered_views
|
||||||
|
.keys()
|
||||||
|
.copied()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for view_id in view_ids {
|
||||||
|
if !invalidation.updated.contains(&view_id) {
|
||||||
|
let window_id = self.window_id;
|
||||||
|
let titlebar_height = self.window.titlebar_height;
|
||||||
|
let hovered_region_ids = self.window.hovered_region_ids.clone();
|
||||||
|
let clicked_region_ids = self
|
||||||
|
.window
|
||||||
|
.clicked_button
|
||||||
|
.map(|button| (self.window.clicked_region_ids.clone(), button));
|
||||||
|
let element = self
|
||||||
|
.render_view(RenderParams {
|
||||||
|
window_id,
|
||||||
|
view_id,
|
||||||
|
titlebar_height,
|
||||||
|
hovered_region_ids,
|
||||||
|
clicked_region_ids,
|
||||||
|
refreshing: true,
|
||||||
|
appearance,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
self.window.rendered_views.insert(view_id, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_scene(&mut self, refreshing: bool) -> Scene {
|
||||||
|
let window_size = self.window.platform_window.content_size();
|
||||||
|
let scale_factor = self.window.platform_window.scale_factor();
|
||||||
|
|
||||||
|
let mut scene_builder = SceneBuilder::new(scale_factor);
|
||||||
|
|
||||||
|
if let Some(root_view_id) = self.root_view_id(self.window_id) {
|
||||||
|
self.layout(window_size, refreshing, self);
|
||||||
|
let mut paint_cx = self.build_paint_context(&mut scene_builder, window_size);
|
||||||
|
paint_cx.paint(
|
||||||
|
root_view_id,
|
||||||
|
Vector2F::zero(),
|
||||||
|
RectF::new(Vector2F::zero(), window_size),
|
||||||
|
);
|
||||||
|
self.window.text_layout_cache.finish_frame();
|
||||||
|
let scene = scene_builder.build();
|
||||||
|
self.window.cursor_regions = scene.cursor_regions();
|
||||||
|
self.window.mouse_regions = scene.mouse_regions();
|
||||||
|
|
||||||
|
// window.is_topmost for the mouse moved event's postion?
|
||||||
|
if self.window_is_active(self.window_id) {
|
||||||
|
if let Some(event) = self.window.last_mouse_moved_event.clone() {
|
||||||
|
self.dispatch_event(event, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scene
|
||||||
|
} else {
|
||||||
|
log::error!("could not find root_view_id for window {}", self.window_id);
|
||||||
|
scene_builder.build()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout(&mut self, window_size: Vector2F, refreshing: bool, cx: &mut AppContext) {
|
||||||
|
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
|
||||||
|
self.build_layout_context(window_size, refreshing, cx)
|
||||||
|
.layout(root_view_id, SizeConstraint::strict(window_size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_layout_context<'c>(
|
||||||
|
&'c mut self,
|
||||||
|
window_size: Vector2F,
|
||||||
|
refreshing: bool,
|
||||||
|
cx: &'c mut AppContext,
|
||||||
|
) -> LayoutContext<'c> {
|
||||||
|
LayoutContext {
|
||||||
|
window_id: self.window_id,
|
||||||
|
rendered_views: &mut self.window.rendered_views,
|
||||||
|
font_cache: &self.font_cache,
|
||||||
|
font_system: cx.platform().fonts(),
|
||||||
|
text_layout_cache: &self.window.text_layout_cache,
|
||||||
|
asset_cache: &self.window.asset_cache,
|
||||||
|
view_stack: Vec::new(),
|
||||||
|
refreshing,
|
||||||
|
hovered_region_ids: self.window.hovered_region_ids.clone(),
|
||||||
|
clicked_region_ids: self
|
||||||
|
.window
|
||||||
|
.clicked_button
|
||||||
|
.map(|button| (self.window.clicked_region_ids.clone(), button)),
|
||||||
|
titlebar_height: self.window.titlebar_height,
|
||||||
|
appearance: self.window.appearance,
|
||||||
|
window_size,
|
||||||
app: cx,
|
app: cx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_elements(&self, cx: &AppContext) -> Option<json::Value> {
|
pub fn build_paint_context<'c>(
|
||||||
let view = cx.root_view(self.window_id)?;
|
&'c mut self,
|
||||||
|
scene: &'c mut SceneBuilder,
|
||||||
|
window_size: Vector2F,
|
||||||
|
) -> PaintContext {
|
||||||
|
PaintContext {
|
||||||
|
scene,
|
||||||
|
window_size,
|
||||||
|
font_cache: &self.font_cache,
|
||||||
|
text_layout_cache: &self.window.text_layout_cache,
|
||||||
|
rendered_views: &mut self.window.rendered_views,
|
||||||
|
view_stack: Vec::new(),
|
||||||
|
app: self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rect_for_text_range(&self, range_utf16: Range<usize>) -> Option<RectF> {
|
||||||
|
self.focused_view_id(self.window_id).and_then(|view_id| {
|
||||||
|
let cx = MeasurementContext {
|
||||||
|
app: self,
|
||||||
|
rendered_views: &self.window.rendered_views,
|
||||||
|
window_id: self.window_id,
|
||||||
|
};
|
||||||
|
cx.rect_for_text_range(view_id, range_utf16)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn debug_elements(&self) -> Option<json::Value> {
|
||||||
|
let view = self.root_view(self.window_id)?;
|
||||||
Some(json!({
|
Some(json!({
|
||||||
"root_view": view.debug_json(cx),
|
"root_view": view.debug_json(self),
|
||||||
"root_element": self.rendered_views.get(&view.id())
|
"root_element": self.window.rendered_views.get(&view.id())
|
||||||
.map(|root_element| {
|
.map(|root_element| {
|
||||||
root_element.debug(&DebugContext {
|
root_element.debug(&DebugContext {
|
||||||
rendered_views: &self.rendered_views,
|
rendered_views: &self.window.rendered_views,
|
||||||
font_cache: &self.font_cache,
|
font_cache: &self.window.font_cache,
|
||||||
app: cx,
|
app: self,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_window_title(&mut self, title: &str) {
|
||||||
|
self.window.platform_window.set_title(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_window_edited(&mut self, edited: bool) {
|
||||||
|
self.window.platform_window.set_edited(edited);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_topmost_window_for_position(&self, position: Vector2F) -> bool {
|
||||||
|
self.window
|
||||||
|
.platform_window
|
||||||
|
.is_topmost_for_position(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn activate_window(&self) {
|
||||||
|
self.window.platform_window.activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window_bounds(&self) -> WindowBounds {
|
||||||
|
self.window.platform_window.bounds()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window_display_uuid(&self) -> Option<Uuid> {
|
||||||
|
self.window.platform_window.screen().display_uuid()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_character_palette(&self) {
|
||||||
|
self.window.platform_window.show_character_palette();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn minimize_window(&self) {
|
||||||
|
self.window.platform_window.minimize();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn zoom_window(&self) {
|
||||||
|
self.window.platform_window.zoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn toggle_window_full_screen(&self) {
|
||||||
|
self.window.platform_window.toggle_full_screen();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prompt(
|
||||||
|
&self,
|
||||||
|
level: PromptLevel,
|
||||||
|
msg: &str,
|
||||||
|
answers: &[&str],
|
||||||
|
) -> oneshot::Receiver<usize> {
|
||||||
|
self.window.platform_window.prompt(level, msg, answers)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct LayoutContext<'a> {
|
pub struct LayoutContext<'a> {
|
|
@ -90,8 +90,9 @@ impl InputHandler for WindowInputHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rect_for_range(&self, range_utf16: Range<usize>) -> Option<RectF> {
|
fn rect_for_range(&self, range_utf16: Range<usize>) -> Option<RectF> {
|
||||||
let app = self.app.borrow();
|
self.app
|
||||||
let window = app.windows.get(&self.window_id)?;
|
.borrow_mut()
|
||||||
window.presenter.rect_for_text_range(range_utf16, &app)
|
.update_window(self.window_id, |cx| cx.rect_for_text_range(range_utf16))
|
||||||
|
.flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,16 +26,14 @@ pub use self::{
|
||||||
stack::*, svg::*, text::*, tooltip::*, uniform_list::*,
|
stack::*, svg::*, text::*, tooltip::*, uniform_list::*,
|
||||||
};
|
};
|
||||||
use self::{clipped::Clipped, expanded::Expanded};
|
use self::{clipped::Clipped, expanded::Expanded};
|
||||||
pub use crate::presenter::ChildView;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
app::window::MeasurementContext,
|
||||||
geometry::{
|
geometry::{
|
||||||
rect::RectF,
|
rect::RectF,
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json,
|
json, Action, DebugContext, EventContext, LayoutContext, PaintContext, RenderContext,
|
||||||
presenter::MeasurementContext,
|
SizeConstraint, View,
|
||||||
Action, DebugContext, EventContext, LayoutContext, PaintContext, RenderContext, SizeConstraint,
|
|
||||||
View,
|
|
||||||
};
|
};
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use json::ToJson;
|
use json::ToJson;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json,
|
json,
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
use json::ToJson;
|
use json::ToJson;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::Element;
|
use super::Element;
|
||||||
use crate::{
|
use crate::{
|
||||||
json::{self, json},
|
json::{self, json},
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
DebugContext, PaintContext,
|
DebugContext, PaintContext,
|
||||||
};
|
};
|
||||||
use json::ToJson;
|
use json::ToJson;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use serde_json::json;
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json,
|
json,
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ use crate::{
|
||||||
},
|
},
|
||||||
json::ToJson,
|
json::ToJson,
|
||||||
platform::CursorStyle,
|
platform::CursorStyle,
|
||||||
presenter::MeasurementContext,
|
|
||||||
scene::{self, Border, CursorRegion, Quad},
|
scene::{self, Border, CursorRegion, Quad},
|
||||||
|
window::MeasurementContext,
|
||||||
Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{json, ToJson},
|
json::{json, ToJson},
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
DebugContext,
|
DebugContext,
|
||||||
};
|
};
|
||||||
use crate::{Element, LayoutContext, PaintContext, SizeConstraint};
|
use crate::{Element, LayoutContext, PaintContext, SizeConstraint};
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::ops::Range;
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json,
|
json,
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::{any::Any, cell::Cell, f32::INFINITY, ops::Range, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
json::{self, ToJson, Value},
|
json::{self, ToJson, Value},
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
Axis, DebugContext, Element, ElementBox, ElementStateHandle, LayoutContext, PaintContext,
|
Axis, DebugContext, Element, ElementBox, ElementStateHandle, LayoutContext, PaintContext,
|
||||||
RenderContext, SizeConstraint, Vector2FExt, View,
|
RenderContext, SizeConstraint, Vector2FExt, View,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::ops::Range;
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json::json,
|
json::json,
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,9 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{json, ToJson},
|
json::{json, ToJson},
|
||||||
presenter::MeasurementContext,
|
scene,
|
||||||
scene, Border, DebugContext, Element, ImageData, LayoutContext, PaintContext, SizeConstraint,
|
window::MeasurementContext,
|
||||||
|
Border, DebugContext, Element, ImageData, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{ops::Range, sync::Arc};
|
use std::{ops::Range, sync::Arc};
|
||||||
|
|
|
@ -7,8 +7,8 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{ToJson, Value},
|
json::{ToJson, Value},
|
||||||
presenter::MeasurementContext,
|
|
||||||
text_layout::{Line, RunStyle},
|
text_layout::{Line, RunStyle},
|
||||||
|
window::MeasurementContext,
|
||||||
DebugContext, Element, LayoutContext, PaintContext, SizeConstraint,
|
DebugContext, Element, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::json,
|
json::json,
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
DebugContext, Element, ElementBox, ElementRc, EventContext, LayoutContext, MouseRegion,
|
DebugContext, Element, ElementBox, ElementRc, EventContext, LayoutContext, MouseRegion,
|
||||||
PaintContext, RenderContext, SizeConstraint, View, ViewContext,
|
PaintContext, RenderContext, SizeConstraint, View, ViewContext,
|
||||||
};
|
};
|
||||||
|
@ -631,7 +631,6 @@ mod tests {
|
||||||
|
|
||||||
#[crate::test(self)]
|
#[crate::test(self)]
|
||||||
fn test_layout(cx: &mut crate::AppContext) {
|
fn test_layout(cx: &mut crate::AppContext) {
|
||||||
let mut presenter = cx.build_presenter(0, 0., Default::default());
|
|
||||||
let (_, view) = cx.add_window(Default::default(), |_| TestView);
|
let (_, view) = cx.add_window(Default::default(), |_| TestView);
|
||||||
let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.));
|
let constraint = SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.));
|
||||||
|
|
||||||
|
@ -730,8 +729,7 @@ mod tests {
|
||||||
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
|
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
|
||||||
.unwrap_or(10);
|
.unwrap_or(10);
|
||||||
|
|
||||||
let (_, view) = cx.add_window(Default::default(), |_| TestView);
|
let (window_id, view) = cx.add_window(Default::default(), |_| TestView);
|
||||||
let mut presenter = cx.build_presenter(0, 0., Default::default());
|
|
||||||
let mut next_id = 0;
|
let mut next_id = 0;
|
||||||
let elements = Rc::new(RefCell::new(
|
let elements = Rc::new(RefCell::new(
|
||||||
(0..rng.gen_range(0..=20))
|
(0..rng.gen_range(0..=20))
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::ops::Range;
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json::ToJson,
|
json::ToJson,
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
Axis, DebugContext, Element, ElementBox, LayoutContext, MouseRegion, PaintContext,
|
Axis, DebugContext, Element, ElementBox, LayoutContext, MouseRegion, PaintContext,
|
||||||
SizeConstraint,
|
SizeConstraint,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::ops::Range;
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json::{self, json, ToJson},
|
json::{self, json, ToJson},
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
DebugContext, Element, ElementBox, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,9 @@ use crate::{
|
||||||
rect::RectF,
|
rect::RectF,
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
presenter::MeasurementContext,
|
scene,
|
||||||
scene, DebugContext, Element, LayoutContext, PaintContext, SizeConstraint,
|
window::MeasurementContext,
|
||||||
|
DebugContext, Element, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Svg {
|
pub struct Svg {
|
||||||
|
|
|
@ -6,8 +6,8 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{ToJson, Value},
|
json::{ToJson, Value},
|
||||||
presenter::MeasurementContext,
|
|
||||||
text_layout::{Line, RunStyle, ShapedBoundary},
|
text_layout::{Line, RunStyle, ShapedBoundary},
|
||||||
|
window::MeasurementContext,
|
||||||
DebugContext, Element, FontCache, LayoutContext, PaintContext, SizeConstraint, TextLayoutCache,
|
DebugContext, Element, FontCache, LayoutContext, PaintContext, SizeConstraint, TextLayoutCache,
|
||||||
};
|
};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
@ -271,12 +271,18 @@ pub fn layout_highlighted_chunks<'a>(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{elements::Empty, fonts, AppContext, ElementBox, Entity, RenderContext, View};
|
use crate::{
|
||||||
|
elements::Empty, fonts, platform, AppContext, ElementBox, Entity, RenderContext, View,
|
||||||
|
};
|
||||||
|
|
||||||
#[crate::test(self)]
|
#[crate::test(self)]
|
||||||
fn test_soft_wrapping_with_carriage_returns(cx: &mut AppContext) {
|
fn test_soft_wrapping_with_carriage_returns(cx: &mut AppContext) {
|
||||||
let (window_id, _) = cx.add_window(Default::default(), |_| TestView);
|
let (window_id, root_view) = cx.add_window(Default::default(), |_| TestView);
|
||||||
let mut presenter = cx.build_presenter(window_id, Default::default(), Default::default());
|
let mut presenter = cx.build_window(
|
||||||
|
window_id,
|
||||||
|
root_view.into_any(),
|
||||||
|
Box::new(platform::test::Window::new(Vector2F::new(800., 600.))),
|
||||||
|
);
|
||||||
fonts::with_font_cache(cx.font_cache().clone(), || {
|
fonts::with_font_cache(cx.font_cache().clone(), || {
|
||||||
let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true);
|
let mut text = Text::new("Hello\r\n", Default::default()).with_soft_wrap(true);
|
||||||
let (_, state) = text.layout(
|
let (_, state) = text.layout(
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
fonts::TextStyle,
|
fonts::TextStyle,
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json::json,
|
json::json,
|
||||||
presenter::MeasurementContext,
|
window::MeasurementContext,
|
||||||
Action, Axis, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint,
|
Action, Axis, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint,
|
||||||
Task, View,
|
Task, View,
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,8 +6,8 @@ use crate::{
|
||||||
},
|
},
|
||||||
json::{self, json},
|
json::{self, json},
|
||||||
platform::ScrollWheelEvent,
|
platform::ScrollWheelEvent,
|
||||||
presenter::MeasurementContext,
|
|
||||||
scene::MouseScrollWheel,
|
scene::MouseScrollWheel,
|
||||||
|
window::MeasurementContext,
|
||||||
ElementBox, MouseRegion, RenderContext, View,
|
ElementBox, MouseRegion, RenderContext, View,
|
||||||
};
|
};
|
||||||
use json::ToJson;
|
use json::ToJson;
|
||||||
|
|
|
@ -14,7 +14,6 @@ mod clipboard;
|
||||||
pub use clipboard::ClipboardItem;
|
pub use clipboard::ClipboardItem;
|
||||||
pub mod fonts;
|
pub mod fonts;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
mod presenter;
|
|
||||||
pub mod scene;
|
pub mod scene;
|
||||||
pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder};
|
pub use scene::{Border, CursorRegion, MouseRegion, MouseRegionId, Quad, Scene, SceneBuilder};
|
||||||
pub mod text_layout;
|
pub mod text_layout;
|
||||||
|
@ -28,7 +27,7 @@ pub mod json;
|
||||||
pub mod keymap_matcher;
|
pub mod keymap_matcher;
|
||||||
pub mod platform;
|
pub mod platform;
|
||||||
pub use gpui_macros::test;
|
pub use gpui_macros::test;
|
||||||
pub use presenter::{
|
pub use window::{
|
||||||
Axis, DebugContext, EventContext, LayoutContext, MeasurementContext, PaintContext,
|
Axis, DebugContext, EventContext, LayoutContext, MeasurementContext, PaintContext,
|
||||||
SizeConstraint, Vector2FExt,
|
SizeConstraint, Vector2FExt,
|
||||||
};
|
};
|
||||||
|
|
|
@ -261,7 +261,7 @@ pub struct Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
fn new(size: Vector2F) -> Self {
|
pub fn new(size: Vector2F) -> Self {
|
||||||
Self {
|
Self {
|
||||||
size,
|
size,
|
||||||
event_handlers: Default::default(),
|
event_handlers: Default::default(),
|
||||||
|
|
Loading…
Reference in a new issue