Original commit: bfe5377ba5
This commit is contained in:
Danilo Guanabara 2020-02-18 14:40:24 -03:00 committed by GitHub
parent 6897884a9e
commit a9f2de5b00
25 changed files with 692 additions and 25 deletions

View File

@ -14,6 +14,7 @@ members = [
"lib/ide/ast/macros",
"lib/ide/file-manager",
"lib/ide/file-manager/mock-server",
"lib/ide/",
"lib/ide/json-rpc",
"lib/ide/parser",
"lib/ide/utils",

View File

@ -73,7 +73,7 @@ async function download_content(cfg) {
// ====================
/// The name of the main scene in the WASM binary.
let main_scene_name = 'shapes'
let main_scene_name = 'ide'
/// Prefix name of each scene defined in the WASM binary.
let wasm_fn_pfx = "run_example_"

View File

@ -27,7 +27,7 @@ use wasm_bindgen::prelude::Closure;
/// Add initialization callback
///
/// The callback passed as argument will be called once the msdfgen libirary
/// The callback passed as argument will be called once the msdfgen library
/// will be initialized.
pub fn run_once_initialized<F>(callback:F)
where F : 'static + FnOnce() {

View File

@ -242,7 +242,7 @@ impl PhysicsProperties {
impl PhysicsProperties {
/// Safe accessor to modify `KinematicsProperties`.
pub fn mod_kinematics<F:FnOnce(&mut KinematicsProperties)>(&mut self, f:F) {
pub fn modify_kinematics<F:FnOnce(&mut KinematicsProperties)>(&mut self, f:F) {
let mut kinematics = self.kinematics();
f(&mut kinematics);
self.set_kinematics(kinematics);
@ -254,7 +254,7 @@ impl PhysicsProperties {
}
/// Safe accessor to modify `SpringProperties`.
pub fn mod_spring<F:FnOnce(&mut SpringProperties)>(&mut self, f:F) {
pub fn modify_spring<F:FnOnce(&mut SpringProperties)>(&mut self, f:F) {
let mut spring = self.spring();
f(&mut spring);
self.set_spring(spring);
@ -266,7 +266,7 @@ impl PhysicsProperties {
}
/// Safe accessor to modify `DragProperties`.
pub fn mod_drag<F:FnOnce(&mut DragProperties)>(&mut self, f:F) {
pub fn modify_drag<F:FnOnce(&mut DragProperties)>(&mut self, f:F) {
let mut drag = self.drag();
f(&mut drag);
self.set_drag(drag);
@ -278,7 +278,7 @@ impl PhysicsProperties {
}
/// Safe accessor to modify `SimulationThresholds`.
pub fn mod_thresholds<F:FnOnce(&mut SimulationThresholds)>(&mut self, f:F) {
pub fn modify_thresholds<F:FnOnce(&mut SimulationThresholds)>(&mut self, f:F) {
let mut thresholds = self.thresholds();
f(&mut thresholds);
self.set_thresholds(thresholds);
@ -362,7 +362,7 @@ impl PhysicsSimulator {
let fixed_point = properties.spring().fixed_point;
let thresholds = properties.thresholds();
properties.mod_kinematics(|kinematics| {
properties.modify_kinematics(|kinematics| {
let speed = kinematics.velocity.magnitude();
let position = kinematics.position();
let distance = (position - fixed_point).magnitude();
@ -398,7 +398,7 @@ fn simulate(properties:&mut PhysicsProperties, delta_ms:f64) -> Vector3<f32> {
let spring = properties.spring();
let drag = properties.drag();
let mut net_force = zero();
properties.mod_kinematics(|mut kinematics| {
properties.modify_kinematics(|mut kinematics| {
net_force += spring.force(&kinematics);
net_force += drag.force(&kinematics);
let delta_seconds = delta_ms / 1000.0;

View File

@ -7,7 +7,9 @@ use crate::data::dirty;
use crate::display::layout::types::*;
use crate::display::object::DisplayObjectData;
use crate::data::dirty::traits::*;
use crate::control::callback::{XCallbackRegistry1, CallbackHandle, XCallbackMut1Fn};
use crate::control::callback::XCallbackRegistry1;
use crate::control::callback::XCallbackMut1Fn;
use crate::control::callback::CallbackHandle;
use nalgebra::Vector2;
use nalgebra::Vector3;

View File

@ -93,18 +93,18 @@ impl Navigator {
let y = pan.movement.y * scale;
let z = 0.0;
properties.mod_spring(|spring| { spring.fixed_point += Vector3::new(x, y, z); });
properties.modify_spring(|spring| { spring.fixed_point += Vector3::new(x, y, z); });
});
let transform = camera.transform();
let resize_callback = camera.add_screen_update_callback(
enclose!((mut properties,transform) move |_:&Vector2<f32>| {
let position = transform.position();
properties.mod_kinematics(|kinematics| {
properties.modify_kinematics(|kinematics| {
kinematics.set_position(position);
kinematics.set_velocity(Vector3::new(0.0, 0.0, 0.0));
});
properties.mod_spring(|spring| spring.fixed_point = position);
properties.modify_spring(|spring| spring.fixed_point = position);
})
);
@ -126,7 +126,7 @@ impl Navigator {
let min_zoom = camera.clipping().near + min_zoom;
position.z = clamp(position.z, min_zoom, max_zoom);
properties.mod_spring(|spring| spring.fixed_point = position);
properties.modify_spring(|spring| spring.fixed_point = position);
};
(resize_callback, NavigatorEvents::new(dom, panning_callback, zoom_callback, zoom_speed))
}

View File

@ -42,6 +42,7 @@ pub struct TextFieldProperties {
/// Text size being a line height in pixels.
pub text_size: f32,
/// Base color of displayed text.
//TODO: base_color should use definitions in core/data/color
pub base_color: Vector4<f32>,
/// Size of this component.
pub size: Vector2<f32>,
@ -83,6 +84,16 @@ shared! { TextField
self.display_object.set_position(position);
}
/// Get position of this TextField.
pub fn position(&self) -> Vector3<f32> {
self.display_object.position()
}
/// Get size.
pub fn size(&self) -> Vector2<f32> {
self.properties.size
}
/// Scroll text by given offset in pixels.
pub fn scroll(&mut self, offset:Vector2<f32>) {
let position_change = -Vector3::new(offset.x,offset.y,0.0);

View File

@ -77,7 +77,7 @@ mod tests {
let y = 240.0 * random() as f32;
let z = 0.0;
let position = Vector3::new(x, y, z);
properties.mod_spring(|spring| spring.fixed_point = position);
properties.modify_spring(|spring| spring.fixed_point = position);
target.mod_position(|t| *t = position);
});

View File

@ -7,12 +7,12 @@ edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
basegl = { version = "0.1.0" , path = "../core" }
basegl-core-msdf-sys = { version = "0.1.0" , path = "../core/msdf-sys" }
basegl-system-web = { version = "0.1.0" , path = "../system/web" }
enso-frp = { version = "0.1.0" , path = "../frp" }
enso-frp = { version = "0.1.0" , path = "../frp" }
ide = { version = "0.1.0" , path = "../ide" }
enso-prelude = { version = "0.1.0" , path = "../prelude" }
wasm-bindgen = { version = "0.2.58" , features = ["nightly"] }

View File

@ -10,9 +10,9 @@ use basegl::display::object::DisplayObjectOps;
use basegl::display::symbol::geometry::Sprite;
use basegl::display::symbol::geometry::SpriteSystem;
use basegl::display::world::*;
use basegl::display::navigation::navigator::Navigator;
use basegl::prelude::*;
use basegl::animation::animator::fixed_step::FixedStepAnimator;
use basegl::display::navigation::navigator::Navigator;
use nalgebra::Vector2;
use nalgebra::Vector3;

25
gui/lib/gui/src/ide.rs Normal file
View File

@ -0,0 +1,25 @@
//! This module defines the entrypoint function for IDE.
use wasm_bindgen::prelude::*;
use basegl::system::web;
use ide::run_ide;
/// IDE startup function.
#[wasm_bindgen]
#[allow(dead_code)]
pub fn run_example_ide() {
web::forward_panic_hook_to_console();
web::set_stdout();
// FIXME: This code is temporary. It's used to remove the loader UI.
basegl_core_msdf_sys::run_once_initialized(|| {
web::get_element_by_id("loader").map(|t| {
t.parent_node().map(|p| {
p.remove_child(&t).unwrap()
})
}).ok();
run_ide()
});
}

View File

@ -25,5 +25,6 @@ pub mod sprite_system;
pub mod text_field;
pub mod text_typing;
pub mod css3d_system;
pub mod ide;
use enso_prelude as prelude;

46
gui/lib/ide/Cargo.toml Normal file
View File

@ -0,0 +1,46 @@
[package]
name = "ide"
version = "0.1.0"
authors = ["Enso Team <contact@luna-lang.org>"]
edition = "2018"
[lib]
crate-type = ["cdylib", "rlib"]
[dependencies]
basegl = { version = "0.1.0" , path = "../core" }
enso-prelude = { version = "0.1.0" , path = "../prelude" }
file-manager-client = { version = "0.1.0" , path = "file-manager" }
json-rpc = { version = "0.1.0" , path = "json-rpc" }
utils = { version = "0.1.0" , path = "utils" }
basegl-core-msdf-sys = { version = "0.1.0" , path = "../core/msdf-sys" }
shapely = { version = "0.1.0" , path = "../shapely/impl" }
console_error_panic_hook = { version = "0.1.6" }
futures = { version = "0.3.1" }
nalgebra = { version = "0.19.0" }
js-sys = { version = "0.3.35" }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
uuid = { version = "0.8", features = ["serde", "v5"] }
wasm-bindgen = { version = "0.2.58" }
wasm-bindgen-test = { version = "0.3.8" }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
websocket = "0.23.0"
[dependencies.web-sys]
version = "0.3.22"
features = [
'Blob',
'console',
'CloseEvent',
'Document',
'Element',
"ErrorEvent",
"MessageEvent",
'HtmlElement',
'Node',
'WebSocket',
'Window',
]

View File

@ -321,6 +321,7 @@ impl<Notification> Handler<Notification> {
match event {
TransportEvent::TextMessage(msg) =>
self.process_incoming_message(msg),
TransportEvent::Opened => {}
TransportEvent::Closed => {
// Dropping all ongoing calls will cancel their futures.
self.clear_ongoing_requests();

View File

@ -25,6 +25,8 @@ pub trait Transport : Debug {
pub enum TransportEvent {
/// A text message with has been received.
TextMessage(String),
/// A socket has been opened.
Opened,
/// A socket has been closed by the peer.
Closed,
}

View File

34
gui/lib/ide/src/lib.rs Normal file
View File

@ -0,0 +1,34 @@
//! Main library crate for IDE. It includes implementation of
//! controllers, view logic and code that wraps them all together.
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unsafe_code)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#[allow(unused)]
pub mod todo;
pub mod view;
#[allow(missing_docs)]
/// Common types that should be visible across the whole IDE crate.
pub mod prelude {
pub use enso_prelude::*;
pub use futures::Future;
pub use futures::FutureExt;
pub use futures::Stream;
pub use futures::StreamExt;
pub use futures::task::LocalSpawnExt;
}
use view::project::ProjectView;
/// This function is the IDE entry point responsible for setting up all views and controllers.
pub fn run_ide() {
ProjectView::new().forget();
}

View File

@ -0,0 +1,105 @@
//! TODO [mwu] This module is still provisional work in progress. Currently
//! provided only for tests purposes, needs to be completed and
//! properly reviewed.
//!
//! Module providing the executor-related types and functions.
#![allow(missing_docs)] // TODO [mwu] remove once module is done
use crate::prelude::*;
use futures::task::LocalSpawnExt;
use futures::task::LocalSpawn;
use futures::task::LocalFutureObj;
use futures::task::SpawnError;
use futures::executor::LocalPool;
use futures::executor::LocalSpawner;
use basegl::control::callback::CallbackHandle;
use basegl::control::EventLoop;
// TODO [mwu] If anything, likely thread local variable should be preferred.
static mut CURRENT_SPAWNER: Option<Box<dyn LocalSpawn>> = None;
// TODO [mwu] consider whether it is the "current" spawner or rather
// "the global" spawner. Is it available from outside the async
// context? Do we allow using more than one executor in the IDE?
#[allow(unsafe_code)]
pub fn set_global_spawner(spawner: impl LocalSpawn + 'static) {
unsafe {
CURRENT_SPAWNER = Some(Box::new(spawner));
}
}
#[allow(unsafe_code)]
pub fn unset_global_spawner() {
unsafe {
CURRENT_SPAWNER = None;
}
}
#[allow(unsafe_code)]
pub fn current_spawner() -> &'static mut dyn LocalSpawn {
unsafe {
CURRENT_SPAWNER.as_mut().expect("no global executor has been provided")
}
}
/// Spawn a task scheduled within a current executor.
/// Panics, if called when there is no active asynchronous execution.
pub fn spawn_task(f:impl Future<Output=()> + 'static) {
current_spawner().spawn_local(f).ok();
}
#[derive(Debug)]
pub struct JsExecutor {
_executor : Rc<RefCell<LocalPool>>,
_event_loop : EventLoop,
spawner : LocalSpawner,
_cb_handle : CallbackHandle,
}
impl JsExecutor {
pub fn new(_event_loop:EventLoop) -> JsExecutor {
let _executor = LocalPool::default();
let spawner = _executor.spawner();
let _executor = Rc::new(RefCell::new(_executor));
let _cb_handle = JsExecutor::schedule_execution(_event_loop.clone(), _executor.clone());
JsExecutor {_executor,_event_loop,spawner,_cb_handle}
}
pub fn schedule_execution
(event_loop:EventLoop, executor:Rc<RefCell<LocalPool>>) -> CallbackHandle {
event_loop.add_callback(move |_| {
// Safe, because this is the only place borrowing executor and loop
// callback shall never be re-entrant.
let mut executor = executor.borrow_mut();
set_global_spawner(executor.spawner());
executor.run_until_stalled();
unset_global_spawner();
})
}
pub fn spawn
(&self, f:impl Future<Output = ()> + 'static)
-> Result<(), SpawnError> {
self.spawner.spawn_local(f)
}
pub fn add_callback<F:basegl::control::EventLoopCallback>
(&mut self, callback:F) -> CallbackHandle {
self._event_loop.add_callback(callback)
}
}
impl LocalSpawn for JsExecutor {
fn spawn_local_obj(&self, future: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
self.spawner.spawn_local_obj(future)
}
fn status_local(&self) -> Result<(), SpawnError> {
self.spawner.status_local()
}
}

View File

@ -0,0 +1,3 @@
//! Provisional modules being work in progress.
pub mod executor;

15
gui/lib/ide/src/view.rs Normal file
View File

@ -0,0 +1,15 @@
//! A module containing view components.
#![warn(unsafe_code)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
pub mod temporary_panel;
pub mod project;
pub mod layout;
pub mod text_editor;

View File

@ -0,0 +1,178 @@
//! This module contains implementation of ViewLayout with a single TextEditor temporarily
//! occupying half bottom of the screen as the default layout.
use wasm_bindgen::prelude::*;
use basegl::prelude::*;
use crate::view::temporary_panel::TemporaryPadding;
use crate::view::text_editor::TextEditor;
use crate::view::temporary_panel::TemporaryPanel;
use basegl::system::web::*;
use basegl::display::world::World;
use js_sys::Function;
use nalgebra::zero;
use nalgebra::Vector2;
use std::rc::Rc;
use std::cell::RefCell;
use wasm_bindgen::JsCast;
use web_sys::KeyboardEvent;
use web_sys::HtmlElement;
// ==================
// === LayoutMode ===
// ==================
//TODO: LayoutMode is a temporary enumeration, it will be replaced by proper Panel impl.
/// Defines the element's layout mode. It can fully occupy the screen or only half of it.
#[derive(Clone,Copy,Debug)]
pub enum LayoutMode {
#[allow(missing_docs)]
Full,
#[allow(missing_docs)]
Half
}
impl Default for LayoutMode {
fn default() -> Self {
Self::Half
}
}
// ========================
// === KeyboardListener ===
// ========================
type KeyboardClosure = Closure<dyn FnMut(KeyboardEvent)>;
#[derive(Debug)]
struct KeyboardListener {
callback : KeyboardClosure,
element : HtmlElement,
event_type : String
}
impl KeyboardListener {
fn new(element:&HtmlElement, event_type:String, callback:KeyboardClosure) -> Self {
let element = element.clone();
Self {callback,element,event_type}
}
}
impl Drop for KeyboardListener {
fn drop(&mut self) {
let callback : &Function = self.callback.as_ref().unchecked_ref();
self.element.remove_event_listener_with_callback(&self.event_type, callback).ok();
}
}
// ==================
// === ViewLayout ===
// ==================
shared! { ViewLayout
/// Initial implementation of ViewLayout with a single TextEditor. Pressing ctrl+f toggles
/// fullscreen mode.
#[derive(Debug)]
pub struct ViewLayoutData {
text_editor : TextEditor,
key_listener : Option<KeyboardListener>,
layout_mode : LayoutMode,
size : Vector2<f32>
}
impl {
/// Switches LayoutMode between Half and Full.
pub fn switch_layout_mode(&mut self) {
if let LayoutMode::Half = self.layout_mode {
self.set_layout_mode(LayoutMode::Full)
} else {
self.set_layout_mode(LayoutMode::Half)
}
}
/// Sets ViewLayout size.
pub fn set_size(&mut self, size:Vector2<f32>) {
self.size = size;
self.recalculate_layout();
}
}}
// === Private Methods ===
impl ViewLayoutData {
fn set_layout_mode(&mut self, layout_mode:LayoutMode) {
self.layout_mode = layout_mode;
self.recalculate_layout();
}
fn recalculate_layout(&mut self) {
let size = self.size;
let (position,size) = match self.layout_mode {
LayoutMode::Full => {
let position = Vector2::new(0.0,size.y);
(position,size)
},
LayoutMode::Half => {
let position = Vector2::new(0.0,size.y / 2.0);
let size = Vector2::new(size.x,size.y / 2.0);
(position,size)
}
};
let padding = TemporaryPadding {
left : 10.0,
top : 0.0,
right : 10.0,
bottom : 0.0
};
self.text_editor.set_padding(padding);
self.text_editor.set_size(size);
self.text_editor.set_position(position);
self.text_editor.update();
}
}
impl ViewLayout {
/// Creates a new ViewLayout with a single TextEditor.
pub fn default(world:&World) -> Self {
let text_editor = TextEditor::new(&world);
let key_listener = None;
let layout_mode = default();
let size = zero();
let data = ViewLayoutData {text_editor,key_listener,layout_mode,size};
let rc = Rc::new(RefCell::new(data));
Self {rc}.init(world)
}
fn init_keyboard(self) -> Self {
let view_layout = self.clone();
let closure = move |event:KeyboardEvent| {
const F_KEY : u32 = 70;
if event.ctrl_key() && event.key_code() == F_KEY {
view_layout.switch_layout_mode();
event.prevent_default();
}
};
let closure : Box<dyn FnMut(KeyboardEvent)> = Box::new(closure);
let callback = Closure::wrap(closure);
let body = document().unwrap().body().unwrap();
let key_listener = KeyboardListener::new(&body, "keydown".into(), callback);
self.rc.borrow_mut().key_listener = Some(key_listener);
self
}
fn init(self, world:&World) -> Self {
let screen = world.scene().camera().screen();
let size = Vector2::new(screen.width,screen.height);
self.set_size(size);
self.init_keyboard()
}
}

View File

@ -0,0 +1,81 @@
//! This module contains ProjectView, the main view, responsible for managing TextEditor and
//! GraphEditor.
use crate::prelude::*;
use super::layout::ViewLayout;
use basegl::display::world::WorldData;
use basegl::display::world::World;
use basegl::system::web;
use basegl::control::callback::CallbackHandle;
use nalgebra::Vector2;
use shapely::shared;
// ===================
// === ProjectView ===
// ===================
shared! { ProjectView
/// ProjectView is the main view of the project, holding instances of TextEditor and
/// GraphEditor.
#[derive(Debug)]
pub struct ProjectViewData {
world : World,
layout : ViewLayout,
resize_callback: Option<CallbackHandle>
}
impl {
/// Set view size.
pub fn set_size(&mut self, size:Vector2<f32>) {
self.layout.set_size(size);
}
}
}
impl Default for ProjectViewData {
fn default() -> Self {
let world = WorldData::new(&web::body());
let layout = ViewLayout::default(&world);
let resize_callback = None;
ProjectViewData{world,layout,resize_callback}
}
}
impl ProjectView {
/// Create new ProjectView.
pub fn new() -> Self {
let data = default();
Self{rc:data}.init()
}
fn init(self) -> Self {
let scene = self.with_borrowed(|data| data.world.scene());
let weak = self.downgrade();
let resize_callback = scene.camera().add_screen_update_callback(
move |size:&Vector2<f32>| {
if let Some(this) = weak.upgrade() {
this.set_size(*size)
}
}
);
self.with_borrowed(move |data| data.resize_callback = Some(resize_callback));
self
}
/// Forgets ProjectView, so it won't get dropped when it goes out of scope.
pub fn forget(self) {
std::mem::forget(self)
}
}
impl Default for ProjectView {
fn default() -> Self {
Self::new()
}
}

View File

@ -0,0 +1,52 @@
//! This module contains a temporary definition of Panel. There is a plan to implement proper
//! panels in the future.
use nalgebra::Vector2;
// ===============
// === Padding ===
// ===============
/// A struct containing the padding values.
/// This code is temporary and should be used with cautious.
#[derive(Clone,Copy,Debug,Default)]
pub struct TemporaryPadding {
#[allow(missing_docs)]
pub left : f32,
#[allow(missing_docs)]
pub top : f32,
#[allow(missing_docs)]
pub right : f32,
#[allow(missing_docs)]
pub bottom : f32
}
// =============
// === Panel ===
// =============
/// A trait defining a panel interface.
/// This code is temporary and should be used with cautious.
pub trait TemporaryPanel {
/// Sets padding.
fn set_padding(&mut self, padding: TemporaryPadding);
/// Gets padding.
fn padding(&self) -> TemporaryPadding;
/// Sets size.
fn set_size(&mut self, size:Vector2<f32>);
/// Gets size.
fn size(&self) -> Vector2<f32>;
/// Sets position.
fn set_position(&mut self, position:Vector2<f32>);
/// Gets position.
fn position(&self) -> Vector2<f32>;
}

View File

@ -0,0 +1,98 @@
//! This module contains TextEditor, an UiComponent to edit Enso Modules or Text Files.
use crate::prelude::*;
use super::temporary_panel::TemporaryPanel;
use super::temporary_panel::TemporaryPadding;
use basegl::display::object::DisplayObjectOps;
use basegl::display::shape::text::glyph::font::FontRegistry;
use basegl::display::shape::text::text_field::TextField;
use basegl::display::shape::text::text_field::TextFieldProperties;
use basegl::display::world::*;
use nalgebra::Vector2;
use nalgebra::zero;
// ==================
// === TextEditor ===
// ==================
/// TextEditor allows us to edit text files or Enso Modules. Extensible code highlighting is
/// planned to be implemented for it.
#[derive(Clone,Debug)]
pub struct TextEditor {
text_field : TextField,
padding : TemporaryPadding,
position : Vector2<f32>,
size : Vector2<f32>
}
impl TextEditor {
/// Creates a new TextEditor.
pub fn new(world:&World) -> Self {
let scene = world.scene();
let camera = scene.camera();
let screen = camera.screen();
let mut fonts = FontRegistry::new();
let font = fonts.get_or_load_embedded_font("DejaVuSansMono").unwrap();
let padding = default();
let position = zero();
let size = Vector2::new(screen.width, screen.height);
let black = Vector4::new(0.0,0.0,0.0,1.0);
let base_color = black;
let text_size = 16.0;
let properties = TextFieldProperties {font,text_size,base_color,size};
let text_field = TextField::new(&world,properties);
world.add_child(&text_field);
Self {text_field,padding,position,size}.initialize()
}
fn initialize(self) -> Self {
self.update();
self
}
/// Updates the underlying display object.
pub fn update(&self) {
let padding = self.padding;
let position = self.position;
let position = Vector3::new(position.x + padding.left, position.y + padding.bottom, 0.0);
self.text_field.set_position(position);
// TODO: set text field size once the property change will be supported.
// let padding = Vector2::new(padding.left + padding.right, padding.top + padding.bottom);
// self.text_field.set_size(self.dimensions - padding);
self.text_field.update();
}
}
impl TemporaryPanel for TextEditor {
fn set_padding(&mut self, padding: TemporaryPadding) {
self.padding = padding;
}
fn padding(&self) -> TemporaryPadding {
self.padding
}
fn set_size(&mut self, size:Vector2<f32>) {
self.size = size;
self.update();
}
fn size(&self) -> Vector2<f32> {
self.text_field.size()
}
fn set_position(&mut self, position:Vector2<f32>) {
self.position = position;
self.update();
}
fn position(&self) -> Vector2<f32> {
let position = self.text_field.position();
Vector2::new(position.x, position.y)
}
}

View File

@ -212,14 +212,6 @@ macro_rules! shared_struct {
$(#[$($meta)*])*
pub struct [<Weak $name>] <$($params)*> { weak: Weak<RefCell<$name_mut<$($params)*>>> }
impl<$($params)*> $name <$($params)*> {
/// Downgrade the reference to weak ref.
pub fn downgrade(&self) -> [<Weak $name>] <$($params)*> {
let weak = Rc::downgrade(&self.rc);
[<Weak $name>] {weak}
}
}
impl<$($params)*> Clone for [<Weak $name>] <$($params)*> {
fn clone(&self) -> Self {
let weak = self.weak.clone();
@ -236,6 +228,26 @@ macro_rules! shared_struct {
self.weak.upgrade().map(|rc| $name {rc})
}
}
impl<$($params)*> $name <$($params)*> {
/// Downgrade the reference to weak ref.
pub fn downgrade(&self) -> [<Weak $name>] <$($params)*> {
let weak = Rc::downgrade(&self.rc);
[<Weak $name>] {weak}
}
/// Call operation with borrowed data. Should be use in implementation of wrapper
/// only.
fn with_borrowed<F,R>(&self, operation:F) -> R
where F : FnOnce(&mut $name_mut<$($params)*>) -> R {
operation(&mut self.rc.borrow_mut())
}
/// Check if the shared pointer points to the same struct as `other`.
pub fn identity_equals(&self, other:&Self) -> bool {
Rc::ptr_eq(&self.rc,&other.rc)
}
}
}
};
}