This commit is contained in:
Nathan Sobo 2023-04-08 08:01:05 -06:00
parent 9d23a98157
commit 7536645eea
26 changed files with 496 additions and 519 deletions

View file

@ -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);

View file

@ -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.)),

View file

@ -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);
}); });
} }

View file

@ -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 {

View file

@ -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(&region.id()) { if self.window.hovered_region_ids.remove(&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());
@ -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> {

View file

@ -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()
} }
} }

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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,
}; };

View file

@ -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;

View file

@ -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};

View file

@ -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;

View file

@ -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,
}; };

View file

@ -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,
}; };

View file

@ -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};

View file

@ -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;

View file

@ -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))

View file

@ -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,
}; };

View file

@ -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,
}; };

View file

@ -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 {

View file

@ -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(

View file

@ -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,
}; };

View file

@ -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;

View file

@ -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,
}; };

View file

@ -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(),