.gitignore 🔗
@@ -1,2 +1,3 @@
/target
-.DS_Store
+/zed.xcworkspace
+.DS_Store
Nathan Sobo created
Also, handle window resize.
.gitignore | 3
gpui/src/app.rs | 30 ++
gpui/src/platform/mac/app.rs | 4
gpui/src/platform/mac/renderer.rs | 153 +++++++++++++++++
gpui/src/platform/mac/shaders/shaders.h | 2
gpui/src/platform/mac/shaders/shaders.metal | 13 +
gpui/src/platform/mac/window.rs | 194 ++++++++++++----------
gpui/src/platform/mod.rs | 11
gpui/src/scene.rs | 26 ++
9 files changed, 322 insertions(+), 114 deletions(-)
@@ -1,2 +1,3 @@
/target
-.DS_Store
+/zed.xcworkspace
+.DS_Store
@@ -13,7 +13,6 @@ use pathfinder_geometry::{rect::RectF, vector::vec2f};
use smol::{channel, prelude::*};
use std::{
any::{type_name, Any, TypeId},
- borrow,
cell::RefCell,
collections::{HashMap, HashSet, VecDeque},
fmt::{self, Debug},
@@ -292,6 +291,7 @@ type ActionCallback =
type GlobalActionCallback = dyn FnMut(&dyn Any, &mut MutableAppContext);
pub struct MutableAppContext {
+ weak_self: Option<rc::Weak<RefCell<Self>>>,
platform: Arc<dyn platform::App>,
fonts: Arc<FontCache>,
assets: Arc<AssetCache>,
@@ -302,7 +302,6 @@ pub struct MutableAppContext {
next_entity_id: usize,
next_window_id: usize,
next_task_id: usize,
- weak_self: Option<rc::Weak<RefCell<Self>>>,
subscriptions: HashMap<usize, Vec<Subscription>>,
observations: HashMap<usize, Vec<Observation>>,
window_invalidations: HashMap<usize, WindowInvalidation>,
@@ -325,6 +324,7 @@ impl MutableAppContext {
asset_source: impl AssetSource,
) -> Self {
Self {
+ weak_self: None,
platform,
fonts: Arc::new(FontCache::new()),
assets: Arc::new(AssetCache::new(asset_source)),
@@ -339,7 +339,6 @@ impl MutableAppContext {
next_entity_id: 0,
next_window_id: 0,
next_task_id: 0,
- weak_self: None,
subscriptions: HashMap::new(),
observations: HashMap::new(),
window_invalidations: HashMap::new(),
@@ -355,6 +354,10 @@ impl MutableAppContext {
}
}
+ pub fn upgrade(&self) -> App {
+ App(self.weak_self.as_ref().unwrap().upgrade().unwrap())
+ }
+
pub fn downgrade(&self) -> &AppContext {
&self.ctx
}
@@ -624,7 +627,7 @@ impl MutableAppContext {
self.foreground.clone(),
) {
Err(e) => log::error!("error opening window: {}", e),
- Ok(window) => {
+ Ok(mut window) => {
let presenter = Rc::new(RefCell::new(Presenter::new(
window_id,
self.fonts.clone(),
@@ -632,11 +635,26 @@ impl MutableAppContext {
self,
)));
+ {
+ let mut app = self.upgrade();
+ let presenter = presenter.clone();
+ window.on_resize(Box::new(move |window| {
+ app.update(|ctx| {
+ let scene = presenter.borrow_mut().build_scene(
+ window.size(),
+ window.scale_factor(),
+ ctx,
+ );
+ window.present_scene(scene);
+ })
+ }));
+ }
+
self.on_window_invalidated(window_id, move |invalidation, ctx| {
let mut presenter = presenter.borrow_mut();
presenter.invalidate(invalidation, ctx.downgrade());
let scene = presenter.build_scene(window.size(), window.scale_factor(), ctx);
- window.render_scene(scene);
+ window.present_scene(scene);
});
}
}
@@ -1909,7 +1927,7 @@ impl<T> Hash for ModelHandle<T> {
}
}
-impl<T> borrow::Borrow<usize> for ModelHandle<T> {
+impl<T> std::borrow::Borrow<usize> for ModelHandle<T> {
fn borrow(&self) -> &usize {
&self.model_id
}
@@ -33,7 +33,7 @@ impl platform::App for App {
&self,
options: platform::WindowOptions,
executor: Rc<executor::Foreground>,
- ) -> Result<Rc<dyn platform::Window>> {
- Ok(Rc::new(Window::open(options, executor)?))
+ ) -> Result<Box<dyn platform::Window>> {
+ Ok(Box::new(Window::open(options, executor)?))
}
}
@@ -1,14 +1,21 @@
-use anyhow::{anyhow, Result};
+use std::{ffi::c_void, mem};
-use crate::Scene;
+use self::shaders::ToUchar4;
use super::window::RenderContext;
+use crate::{color::ColorU, scene::Layer, Scene};
+use anyhow::{anyhow, Result};
+use metal::{MTLResourceOptions, NSRange};
+use shaders::ToFloat2 as _;
const SHADERS_METALLIB: &'static [u8] =
include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
+const INSTANCE_BUFFER_SIZE: u64 = 1024 * 1024;
pub struct Renderer {
quad_pipeline_state: metal::RenderPipelineState,
+ quad_vertices: metal::Buffer,
+ instances: metal::Buffer,
}
impl Renderer {
@@ -17,6 +24,22 @@ impl Renderer {
.new_library_with_data(SHADERS_METALLIB)
.map_err(|message| anyhow!("error building metal library: {}", message))?;
+ let quad_vertices = [
+ (0., 0.).to_float2(),
+ (1., 0.).to_float2(),
+ (0., 1.).to_float2(),
+ (0., 1.).to_float2(),
+ (1., 0.).to_float2(),
+ (1., 1.).to_float2(),
+ ];
+ let quad_vertices = device.new_buffer_with_data(
+ quad_vertices.as_ptr() as *const c_void,
+ (quad_vertices.len() * mem::size_of::<shaders::vector_float2>()) as u64,
+ MTLResourceOptions::StorageModeManaged,
+ );
+ let instances =
+ device.new_buffer(INSTANCE_BUFFER_SIZE, MTLResourceOptions::StorageModeManaged);
+
Ok(Self {
quad_pipeline_state: build_pipeline_state(
device,
@@ -26,10 +49,78 @@ impl Renderer {
"quad_fragment",
pixel_format,
)?,
+ quad_vertices,
+ instances,
})
}
- pub fn render(&mut self, scene: &Scene, ctx: RenderContext) {}
+ pub fn render(&mut self, scene: &Scene, ctx: &RenderContext) {
+ ctx.command_encoder.set_viewport(metal::MTLViewport {
+ originX: 0.0,
+ originY: 0.0,
+ width: ctx.drawable_size.x() as f64,
+ height: ctx.drawable_size.y() as f64,
+ znear: 0.0,
+ zfar: 1.0,
+ });
+
+ for layer in scene.layers() {
+ self.render_quads(layer, ctx);
+ }
+ }
+
+ fn render_quads(&mut self, layer: &Layer, ctx: &RenderContext) {
+ ctx.command_encoder
+ .set_render_pipeline_state(&self.quad_pipeline_state);
+ ctx.command_encoder.set_vertex_buffer(
+ shaders::GPUIQuadInputIndex_GPUIQuadInputIndexVertices as u64,
+ Some(&self.quad_vertices),
+ 0,
+ );
+ ctx.command_encoder.set_vertex_buffer(
+ shaders::GPUIQuadInputIndex_GPUIQuadInputIndexQuads as u64,
+ Some(&self.instances),
+ 0,
+ );
+ ctx.command_encoder.set_vertex_bytes(
+ shaders::GPUIQuadInputIndex_GPUIQuadInputIndexUniforms as u64,
+ mem::size_of::<shaders::GPUIQuadUniforms>() as u64,
+ [shaders::GPUIQuadUniforms {
+ viewport_size: ctx.drawable_size.to_float2(),
+ }]
+ .as_ptr() as *const c_void,
+ );
+
+ let batch_size = self.instances.length() as usize / mem::size_of::<shaders::GPUIQuad>();
+
+ let buffer_contents = self.instances.contents() as *mut shaders::GPUIQuad;
+ for quad_batch in layer.quads().chunks(batch_size) {
+ for (ix, quad) in quad_batch.iter().enumerate() {
+ log::info!("render {} {:?}", ix, quad);
+ unsafe {
+ *(buffer_contents.offset(ix as isize)) = shaders::GPUIQuad {
+ origin: quad.bounds.origin().to_float2(),
+ size: quad.bounds.size().to_float2(),
+ background_color: quad
+ .background
+ .unwrap_or(ColorU::transparent_black())
+ .to_uchar4(),
+ };
+ }
+ }
+ self.instances.did_modify_range(NSRange {
+ location: 0,
+ length: (quad_batch.len() * mem::size_of::<shaders::GPUIQuad>()) as u64,
+ });
+
+ ctx.command_encoder.draw_primitives_instanced(
+ metal::MTLPrimitiveType::Triangle,
+ 0,
+ 6,
+ quad_batch.len() as u64,
+ );
+ }
+ }
}
fn build_pipeline_state(
@@ -47,7 +138,7 @@ fn build_pipeline_state(
.get_function(fragment_fn_name, None)
.map_err(|message| anyhow!("error locating fragment function: {}", message))?;
- let mut descriptor = metal::RenderPipelineDescriptor::new();
+ let descriptor = metal::RenderPipelineDescriptor::new();
descriptor.set_label(label);
descriptor.set_vertex_function(Some(vertex_fn.as_ref()));
descriptor.set_fragment_function(Some(fragment_fn.as_ref()));
@@ -61,3 +152,57 @@ fn build_pipeline_state(
.new_render_pipeline_state(&descriptor)
.map_err(|message| anyhow!("could not create render pipeline state: {}", message))
}
+
+mod shaders {
+ #![allow(non_upper_case_globals)]
+ #![allow(non_camel_case_types)]
+ #![allow(non_snake_case)]
+
+ use crate::{color::ColorU, geometry::vector::Vector2F};
+ use std::mem;
+
+ include!(concat!(env!("OUT_DIR"), "/shaders.rs"));
+
+ pub trait ToFloat2 {
+ fn to_float2(&self) -> vector_float2;
+ }
+
+ pub trait ToUchar4 {
+ fn to_uchar4(&self) -> vector_uchar4;
+ }
+
+ impl ToFloat2 for (f32, f32) {
+ fn to_float2(&self) -> vector_float2 {
+ unsafe {
+ let mut output = mem::transmute::<_, u32>(self.1.to_bits()) as vector_float2;
+ output <<= 32;
+ output |= mem::transmute::<_, u32>(self.0.to_bits()) as vector_float2;
+ output
+ }
+ }
+ }
+
+ impl ToFloat2 for Vector2F {
+ fn to_float2(&self) -> vector_float2 {
+ unsafe {
+ let mut output = mem::transmute::<_, u32>(self.y().to_bits()) as vector_float2;
+ output <<= 32;
+ output |= mem::transmute::<_, u32>(self.x().to_bits()) as vector_float2;
+ output
+ }
+ }
+ }
+
+ impl ToUchar4 for ColorU {
+ fn to_uchar4(&self) -> vector_uchar4 {
+ let mut vec = self.a as vector_uchar4;
+ vec <<= 8;
+ vec |= self.b as vector_uchar4;
+ vec <<= 8;
+ vec |= self.g as vector_uchar4;
+ vec <<= 8;
+ vec |= self.r as vector_uchar4;
+ vec
+ }
+ }
+}
@@ -9,7 +9,7 @@ typedef enum {
typedef struct {
vector_float2 origin;
vector_float2 size;
- vector_float4 background_color;
+ vector_uchar4 background_color;
} GPUIQuad;
typedef struct {
@@ -3,6 +3,10 @@
using namespace metal;
+float4 coloru_to_colorf(uchar4 coloru) {
+ return float4(coloru) / float4(0xff, 0xff, 0xff, 0xff);
+}
+
struct QuadFragmentInput {
float4 position [[position]];
GPUIQuad quad;
@@ -17,14 +21,15 @@ vertex QuadFragmentInput quad_vertex(
) {
float2 unit_vertex = unit_vertices[unit_vertex_id];
GPUIQuad quad = quads[quad_id];
- float4 position = float4((unit_vertex * quad.size + quad.origin) / (uniforms->viewport_size / 2.0), 0.0, 1.0);
+ float2 position = (unit_vertex * quad.size + quad.origin) / (uniforms->viewport_size / 2.0);
+ float4 device_position = float4(position * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
return QuadFragmentInput {
- position,
+ device_position,
quad,
};
}
fragment float4 quad_fragment(QuadFragmentInput input [[stage_in]]) {
- return input.quad.background_color;
-}
+ return coloru_to_colorf(input.quad.background_color);
+}
@@ -1,7 +1,8 @@
use crate::{
executor,
geometry::vector::Vector2F,
- platform::{self, Event},
+ platform::{self, Event, WindowContext},
+ util::post_inc,
Scene,
};
use anyhow::{anyhow, Result};
@@ -27,7 +28,7 @@ use objc::{
use pathfinder_geometry::vector::vec2f;
use smol::Timer;
use std::{
- cell::{Cell, RefCell},
+ cell::RefCell,
ffi::c_void,
mem, ptr,
rc::Rc,
@@ -111,16 +112,16 @@ unsafe fn build_classes() {
};
}
-pub struct Window(Rc<WindowState>);
+pub struct Window(Rc<RefCell<WindowState>>);
struct WindowState {
native_window: id,
- event_callback: RefCell<Option<Box<dyn FnMut(Event) -> bool>>>,
- resize_callback: RefCell<Option<Box<dyn FnMut(Vector2F, f32)>>>,
- synthetic_drag_counter: Cell<usize>,
+ event_callback: Option<Box<dyn FnMut(Event, &mut dyn platform::WindowContext)>>,
+ resize_callback: Option<Box<dyn FnMut(&mut dyn platform::WindowContext)>>,
+ synthetic_drag_counter: usize,
executor: Rc<executor::Foreground>,
- scene_to_render: RefCell<Option<Scene>>,
- renderer: RefCell<Renderer>,
+ scene_to_render: Option<Scene>,
+ renderer: Renderer,
command_queue: metal::CommandQueue,
device: metal::Device,
layer: id,
@@ -181,18 +182,18 @@ impl Window {
return Err(anyhow!("view return nil from initializer"));
}
- let window = Self(Rc::new(WindowState {
+ let window = Self(Rc::new(RefCell::new(WindowState {
native_window,
- event_callback: RefCell::new(None),
- resize_callback: RefCell::new(None),
- synthetic_drag_counter: Cell::new(0),
+ event_callback: None,
+ resize_callback: None,
+ synthetic_drag_counter: 0,
executor,
scene_to_render: Default::default(),
- renderer: RefCell::new(Renderer::new(&device, PIXEL_FORMAT)?),
+ renderer: Renderer::new(&device, PIXEL_FORMAT)?,
command_queue: device.new_command_queue(),
device,
layer,
- }));
+ })));
(*native_window).set_ivar(
WINDOW_STATE_IVAR,
@@ -236,46 +237,44 @@ impl Window {
pub fn zoom(&self) {
unsafe {
- self.0.native_window.performZoom_(nil);
+ self.0.as_ref().borrow().native_window.performZoom_(nil);
}
}
-
- pub fn on_event<F: 'static + FnMut(Event) -> bool>(&mut self, callback: F) {
- *self.0.event_callback.borrow_mut() = Some(Box::new(callback));
- }
-
- pub fn on_resize<F: 'static + FnMut(Vector2F, f32)>(&mut self, callback: F) {
- *self.0.resize_callback.borrow_mut() = Some(Box::new(callback));
- }
}
impl Drop for Window {
fn drop(&mut self) {
unsafe {
- self.0.native_window.close();
- let _: () = msg_send![self.0.native_window.delegate(), release];
+ self.0.as_ref().borrow().native_window.close();
}
}
}
impl platform::Window for Window {
+ fn on_event(&mut self, callback: Box<dyn FnMut(Event, &mut dyn platform::WindowContext)>) {
+ self.0.as_ref().borrow_mut().event_callback = Some(callback);
+ }
+
+ fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn platform::WindowContext)>) {
+ self.0.as_ref().borrow_mut().resize_callback = Some(callback);
+ }
+}
+
+impl platform::WindowContext for Window {
fn size(&self) -> Vector2F {
- self.0.size()
+ self.0.as_ref().borrow().size()
}
fn scale_factor(&self) -> f32 {
- self.0.scale_factor()
+ self.0.as_ref().borrow().scale_factor()
}
- fn render_scene(&self, scene: Scene) {
- *self.0.scene_to_render.borrow_mut() = Some(scene);
- unsafe {
- let _: () = msg_send![self.0.native_window.contentView(), setNeedsDisplay: YES];
- }
+ fn present_scene(&mut self, scene: Scene) {
+ self.0.as_ref().borrow_mut().present_scene(scene);
}
}
-impl WindowState {
+impl platform::WindowContext for WindowState {
fn size(&self) -> Vector2F {
let NSSize { width, height, .. } =
unsafe { NSView::frame(self.native_window.contentView()) }.size;
@@ -289,16 +288,17 @@ impl WindowState {
}
}
- fn next_synthetic_drag_id(&self) -> usize {
- let next_id = self.synthetic_drag_counter.get() + 1;
- self.synthetic_drag_counter.set(next_id);
- next_id
+ fn present_scene(&mut self, scene: Scene) {
+ self.scene_to_render = Some(scene);
+ unsafe {
+ let _: () = msg_send![self.native_window.contentView(), setNeedsDisplay: YES];
+ }
}
}
-unsafe fn window_state(object: &Object) -> Rc<WindowState> {
+unsafe fn get_window_state(object: &Object) -> Rc<RefCell<WindowState>> {
let raw: *mut c_void = *object.get_ivar(WINDOW_STATE_IVAR);
- let rc1 = Rc::from_raw(raw as *mut WindowState);
+ let rc1 = Rc::from_raw(raw as *mut RefCell<WindowState>);
let rc2 = rc1.clone();
mem::forget(rc1);
rc2
@@ -328,23 +328,25 @@ extern "C" fn dealloc_view(this: &Object, _: Sel) {
}
extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
- let window = unsafe { window_state(this) };
+ let window_state = unsafe { get_window_state(this) };
+ let mut window_state_borrow = window_state.as_ref().borrow_mut();
- let event = unsafe { Event::from_native(native_event, Some(window.size().y())) };
+ let event = unsafe { Event::from_native(native_event, Some(window_state_borrow.size().y())) };
if let Some(event) = event {
match event {
- Event::LeftMouseDragged { position } => schedule_synthetic_drag(&window, position),
+ Event::LeftMouseDragged { position } => {
+ schedule_synthetic_drag(&&window_state, position)
+ }
Event::LeftMouseUp { .. } => {
- window.next_synthetic_drag_id();
+ post_inc(&mut window_state_borrow.synthetic_drag_counter);
}
_ => {}
}
- if let Some(callback) = window.event_callback.borrow_mut().as_mut() {
- if callback(event) {
- return;
- }
+ if let Some(mut callback) = window_state_borrow.event_callback.take() {
+ callback(event, &mut *window_state_borrow);
+ window_state_borrow.event_callback = Some(callback);
}
}
}
@@ -356,55 +358,62 @@ extern "C" fn send_event(this: &Object, _: Sel, native_event: id) {
}
extern "C" fn make_backing_layer(this: &Object, _: Sel) -> id {
- let window = unsafe { window_state(this) };
- window.layer
+ let window_state = unsafe { get_window_state(this) };
+ let window_state = window_state.as_ref().borrow();
+ window_state.layer
}
extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel) {
- let window;
+ let window_state = unsafe { get_window_state(this) };
+ let mut window_state = window_state.as_ref().borrow_mut();
+
unsafe {
- window = window_state(this);
- let _: () = msg_send![window.layer, setContentsScale: window.scale_factor() as f64];
+ let _: () =
+ msg_send![window_state.layer, setContentsScale: window_state.scale_factor() as f64];
}
- if let Some(callback) = window.resize_callback.borrow_mut().as_mut() {
- let size = window.size();
- let scale_factor = window.scale_factor();
- callback(size, scale_factor);
+ if let Some(mut callback) = window_state.resize_callback.take() {
+ callback(&mut *window_state);
+ window_state.resize_callback = Some(callback);
};
}
extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) {
- let window;
- unsafe {
- window = window_state(this);
- if window.size() == vec2f(size.width as f32, size.height as f32) {
- return;
- }
+ let window_state = unsafe { get_window_state(this) };
+ let mut window_state = window_state.as_ref().borrow_mut();
+
+ if window_state.size() == vec2f(size.width as f32, size.height as f32) {
+ return;
+ }
+ unsafe {
let _: () = msg_send![super(this, class!(NSView)), setFrameSize: size];
+ }
- let scale_factor = window.scale_factor() as f64;
- let drawable_size: NSSize = NSSize {
- width: size.width * scale_factor,
- height: size.height * scale_factor,
- };
- let _: () = msg_send![window.layer, setDrawableSize: drawable_size];
+ let scale_factor = window_state.scale_factor() as f64;
+ let drawable_size: NSSize = NSSize {
+ width: size.width * scale_factor,
+ height: size.height * scale_factor,
+ };
+
+ unsafe {
+ let _: () = msg_send![window_state.layer, setDrawableSize: drawable_size];
}
- if let Some(callback) = window.resize_callback.borrow_mut().as_mut() {
- let size = window.size();
- let scale_factor = window.scale_factor();
- callback(size, scale_factor);
+ if let Some(mut callback) = window_state.resize_callback.take() {
+ callback(&mut *window_state);
+ window_state.resize_callback = Some(callback);
};
}
extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
+ log::info!("display layer");
unsafe {
- let window = window_state(this);
+ let window_state = get_window_state(this);
+ let mut window_state = window_state.as_ref().borrow_mut();
- if let Some(scene) = window.scene_to_render.borrow_mut().take() {
- let drawable: &metal::MetalDrawableRef = msg_send![window.layer, nextDrawable];
+ if let Some(scene) = window_state.scene_to_render.take() {
+ let drawable: &metal::MetalDrawableRef = msg_send![window_state.layer, nextDrawable];
let render_pass_descriptor = metal::RenderPassDescriptor::new();
let color_attachment = render_pass_descriptor
@@ -416,14 +425,19 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
color_attachment.set_store_action(MTLStoreAction::Store);
color_attachment.set_clear_color(MTLClearColor::new(0., 0., 0., 1.));
- let command_buffer = window.command_queue.new_command_buffer();
+ let command_queue = window_state.command_queue.clone();
+ let command_buffer = command_queue.new_command_buffer();
let command_encoder = command_buffer.new_render_command_encoder(render_pass_descriptor);
- window.renderer.borrow_mut().render(
+ let size = window_state.size();
+ let scale_factor = window_state.scale_factor();
+ let device = window_state.device.clone();
+
+ window_state.renderer.render(
&scene,
- RenderContext {
- drawable_size: window.size() * window.scale_factor(),
- device: &window.device,
+ &RenderContext {
+ drawable_size: size * scale_factor,
+ device: &device,
command_encoder,
},
);
@@ -432,23 +446,33 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
command_buffer.commit();
command_buffer.wait_until_completed();
drawable.present();
+
+ log::info!("present");
};
}
}
-fn schedule_synthetic_drag(window_state: &Rc<WindowState>, position: Vector2F) {
- let drag_id = window_state.next_synthetic_drag_id();
+fn schedule_synthetic_drag(window_state: &Rc<RefCell<WindowState>>, position: Vector2F) {
let weak_window_state = Rc::downgrade(window_state);
+ let mut window_state = window_state.as_ref().borrow_mut();
+
+ let drag_id = post_inc(&mut window_state.synthetic_drag_counter);
let instant = Instant::now() + Duration::from_millis(16);
+
window_state
.executor
.spawn(async move {
Timer::at(instant).await;
if let Some(window_state) = weak_window_state.upgrade() {
- if window_state.synthetic_drag_counter.get() == drag_id {
- if let Some(callback) = window_state.event_callback.borrow_mut().as_mut() {
+ let mut window_state_borrow = window_state.as_ref().borrow_mut();
+ if window_state_borrow.synthetic_drag_counter == drag_id {
+ if let Some(mut callback) = window_state_borrow.event_callback.take() {
schedule_synthetic_drag(&window_state, position);
- callback(Event::LeftMouseDragged { position });
+ callback(
+ Event::LeftMouseDragged { position },
+ &mut *window_state_borrow,
+ );
+ window_state_borrow.event_callback = Some(callback);
}
}
}
@@ -32,7 +32,7 @@ pub trait App {
&self,
options: WindowOptions,
executor: Rc<executor::Foreground>,
- ) -> Result<Rc<dyn Window>>;
+ ) -> Result<Box<dyn Window>>;
}
pub trait Dispatcher: Send + Sync {
@@ -40,10 +40,15 @@ pub trait Dispatcher: Send + Sync {
fn run_on_main_thread(&self, task: Runnable);
}
-pub trait Window {
+pub trait Window: WindowContext {
+ fn on_event(&mut self, callback: Box<dyn FnMut(Event, &mut dyn WindowContext)>);
+ fn on_resize(&mut self, callback: Box<dyn FnMut(&mut dyn WindowContext)>);
+}
+
+pub trait WindowContext {
fn size(&self) -> Vector2F;
fn scale_factor(&self) -> f32;
- fn render_scene(&self, scene: Scene);
+ fn present_scene(&mut self, scene: Scene);
}
pub struct WindowOptions<'a> {
@@ -6,12 +6,12 @@ pub struct Scene {
}
#[derive(Default)]
-struct Layer {
+pub struct Layer {
clip_bounds: Option<RectF>,
quads: Vec<Quad>,
}
-#[derive(Default)]
+#[derive(Default, Debug)]
pub struct Quad {
pub bounds: RectF,
pub background: Option<ColorU>,
@@ -19,7 +19,7 @@ pub struct Quad {
pub corder_radius: f32,
}
-#[derive(Clone, Copy, Default)]
+#[derive(Clone, Copy, Default, Debug)]
pub struct Border {
pub width: f32,
pub color: Option<ColorU>,
@@ -38,13 +38,19 @@ impl Scene {
}
}
- pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {}
-
- pub fn pop_layer(&mut self) {
- assert!(self.active_layer_stack.len() > 1);
- self.active_layer_stack.pop();
+ pub fn layers(&self) -> &[Layer] {
+ self.layers.as_slice()
}
+ // pub fn push_layer(&mut self, clip_bounds: Option<RectF>) {
+
+ // }
+
+ // pub fn pop_layer(&mut self) {
+ // assert!(self.active_layer_stack.len() > 1);
+ // self.active_layer_stack.pop();
+ // }
+
pub fn push_quad(&mut self, quad: Quad) {
self.active_layer().push_quad(quad)
}
@@ -58,6 +64,10 @@ impl Layer {
fn push_quad(&mut self, quad: Quad) {
self.quads.push(quad);
}
+
+ pub fn quads(&self) -> &[Quad] {
+ self.quads.as_slice()
+ }
}
impl Border {