use std::cell::{LazyCell, RefCell};
use std::{any::Any, ffi::c_void};
mod rect;
pub use rect::Rect;
mod array;
pub use array::Array;
mod dictionary;
pub use dictionary::Dictionary;
mod director;
pub use director::Director;
mod app;
pub use app::App;
mod entity;
pub use entity::Entity;
mod group;
pub use group::Group;
mod observer;
pub use observer::Observer;
mod path;
pub use path::Path;
mod content;
pub use content::Content;
mod scheduler;
pub use scheduler::Scheduler;
mod camera;
pub use camera::{Camera, ICamera};
mod camera_2d;
pub use camera_2d::Camera2D;
mod camera_otho;
pub use camera_otho::CameraOtho;
mod pass;
pub use pass::Pass;
mod effect;
pub use effect::{Effect, IEffect};
mod sprite_effect;
pub use sprite_effect::SpriteEffect;
mod view;
pub use view::View;
mod action_def;
pub use action_def::ActionDef;
mod action;
pub use action::Action;
mod grabber;
pub use grabber::Grabber;
mod node;
pub use node::{INode, Node};
mod texture_2d;
pub use texture_2d::Texture2D;
mod sprite;
pub use sprite::Sprite;
mod grid;
pub use grid::Grid;
mod touch;
pub use touch::Touch;
mod ease;
pub use ease::Ease;
mod label;
pub use label::Label;
mod render_target;
pub use render_target::RenderTarget;
mod clip_node;
pub use clip_node::ClipNode;
mod draw_node;
pub use draw_node::DrawNode;
mod vertex_color;
pub use vertex_color::VertexColor;
mod line;
pub use line::Line;
mod particle;
pub use particle::Particle;
mod playable;
pub use playable::{IPlayable, Playable};
mod model;
pub use model::Model;
mod spine;
pub use spine::Spine;
mod dragon_bone;
pub use dragon_bone::DragonBone;
mod align_node;
pub use align_node::AlignNode;
mod effek_node;
pub use effek_node::EffekNode;
mod physics_world;
pub use tile_node::TileNode;
mod tile_node;
pub use physics_world::{IPhysicsWorld, PhysicsWorld};
mod fixture_def;
pub use fixture_def::FixtureDef;
mod body_def;
pub use body_def::BodyDef;
mod sensor;
pub use sensor::Sensor;
mod body;
pub use body::{Body, IBody};
mod joint_def;
pub use joint_def::JointDef;
mod joint;
pub use joint::{IJoint, Joint};
mod motor_joint;
pub use motor_joint::MotorJoint;
mod move_joint;
pub use move_joint::MoveJoint;
mod cache;
pub use cache::Cache;
mod audio;
pub use audio::Audio;
mod audio_bus;
pub use audio_bus::AudioBus;
mod audio_source;
pub use audio_source::AudioSource;
mod keyboard;
pub use keyboard::Keyboard;
mod mouse;
pub use mouse::Mouse;
mod controller;
pub use controller::Controller;
mod svg;
pub use svg::SVG;
mod dbquery;
pub use dbquery::DBQuery;
mod dbparams;
pub use dbparams::DBParams;
mod dbrecord;
pub use dbrecord::DBRecord;
mod db;
pub use db::DB;
mod work_book;
pub use work_book::WorkBook;
mod work_sheet;
pub use work_sheet::WorkSheet;
mod c_45;
mod q_learner;
pub mod ml {
pub use super::c_45::C45;
pub use super::q_learner::QLearner;
}
mod http_client;
pub use http_client::HttpClient;
mod buffer;
pub mod platformer;
pub use buffer::Buffer;
mod im_gui;
pub use im_gui::ImGui;
mod vgpaint;
pub use vgpaint::VGPaint;
mod nvg;
pub use nvg::Nvg;
mod vgnode;
pub use vgnode::VGNode;
type ObjectFunc = fn(i64) -> Option<Box<dyn IObject>>;
thread_local! {
static OBJECT_MAP: LazyCell<Vec<Option<ObjectFunc>>> = LazyCell::new(|| {
let type_funcs = [
Array::type_info(),
Dictionary::type_info(),
Entity::type_info(),
Group::type_info(),
Observer::type_info(),
Scheduler::type_info(),
Camera::type_info(),
Camera2D::type_info(),
CameraOtho::type_info(),
Pass::type_info(),
Effect::type_info(),
SpriteEffect::type_info(),
Grabber::type_info(),
Action::type_info(),
Node::type_info(),
Texture2D::type_info(),
Sprite::type_info(),
Grid::type_info(),
Touch::type_info(),
Label::type_info(),
RenderTarget::type_info(),
ClipNode::type_info(),
DrawNode::type_info(),
Line::type_info(),
Particle::type_info(),
Playable::type_info(),
Model::type_info(),
Spine::type_info(),
DragonBone::type_info(),
AlignNode::type_info(),
EffekNode::type_info(),
TileNode::type_info(),
PhysicsWorld::type_info(),
FixtureDef::type_info(),
BodyDef::type_info(),
Sensor::type_info(),
Body::type_info(),
JointDef::type_info(),
Joint::type_info(),
MotorJoint::type_info(),
MoveJoint::type_info(),
SVG::type_info(),
AudioBus::type_info(),
AudioSource::type_info(),
ml::QLearner::type_info(),
platformer::ActionUpdate::type_info(),
platformer::Face::type_info(),
platformer::BulletDef::type_info(),
platformer::Bullet::type_info(),
platformer::Visual::type_info(),
platformer::behavior::Tree::type_info(),
platformer::decision::Tree::type_info(),
platformer::Unit::type_info(),
platformer::PlatformCamera::type_info(),
platformer::PlatformWorld::type_info(),
Buffer::type_info(),
VGNode::type_info(),
];
let mut map: Vec<Option<ObjectFunc>> = Vec::new();
for pair in type_funcs.iter() {
let t = pair.0 as usize;
if map.len() < t + 1 {
map.resize(t + 1, None);
}
if map[t].is_some() {
panic!("cpp object type id {} duplicated!", t);
}
map[t] = Some(pair.1);
}
map
});
static FUNC_MAP: RefCell<Vec<Box<dyn FnMut()>>> = RefCell::new(Vec::new());
static FUNC_AVAILABLE: RefCell<Vec<i32>> = RefCell::new(Vec::new());
}
extern "C" {
fn object_get_id(obj: i64) -> i32;
fn object_get_type(obj: i64) -> i32;
fn object_retain(obj: i64);
fn object_release(obj: i64);
fn object_to_node(obj: i64) -> i64;
fn object_to_camera(obj: i64) -> i64;
fn object_to_playable(obj: i64) -> i64;
fn object_to_physics_world(obj: i64) -> i64;
fn object_to_body(obj: i64) -> i64;
fn object_to_joint(obj: i64) -> i64;
fn str_new(len: i32) -> i64;
fn str_len(str: i64) -> i32;
fn str_read(dest: *mut c_void, src: i64);
fn str_write(dest: i64, src: *const c_void);
fn str_release(str: i64);
fn buf_new_i32(len: i32) -> i64;
fn buf_new_i64(len: i32) -> i64;
fn buf_new_f32(len: i32) -> i64;
fn buf_new_f64(len: i32) -> i64;
fn buf_len(v: i64) -> i32;
fn buf_read(dest: *mut c_void, src: i64);
fn buf_write(dest: i64, src: *const c_void);
fn buf_release(v: i64);
fn value_create_i64(value: i64) -> i64;
fn value_create_f64(value: f64) -> i64;
fn value_create_str(value: i64) -> i64;
fn value_create_bool(value: i32) -> i64;
fn value_create_object(value: i64) -> i64;
fn value_create_vec2(value: i64) -> i64;
fn value_create_size(value: i64) -> i64;
fn value_release(value: i64);
fn value_into_i64(value: i64) -> i64;
fn value_into_f64(value: i64) -> f64;
fn value_into_str(value: i64) -> i64;
fn value_into_bool(value: i64) -> i32;
fn value_into_object(value: i64) -> i64;
fn value_into_vec2(value: i64) -> i64;
fn value_into_size(value: i64) -> i64;
fn value_is_i64(value: i64) -> i32;
fn value_is_f64(value: i64) -> i32;
fn value_is_str(value: i64) -> i32;
fn value_is_bool(value: i64) -> i32;
fn value_is_object(value: i64) -> i32;
fn value_is_vec2(value: i64) -> i32;
fn value_is_size(value: i64) -> i32;
fn call_stack_create() -> i64;
fn call_stack_release(info: i64);
fn call_stack_push_i64(info: i64, value: i64);
fn call_stack_push_f64(info: i64, value: f64);
fn call_stack_push_str(info: i64, value: i64);
fn call_stack_push_bool(info: i64, value: i32);
fn call_stack_push_object(info: i64, value: i64);
fn call_stack_push_vec2(info: i64, value: i64);
fn call_stack_push_size(info: i64, value: i64);
fn call_stack_pop_i64(info: i64) -> i64;
fn call_stack_pop_f64(info: i64) -> f64;
fn call_stack_pop_str(info: i64) -> i64;
fn call_stack_pop_bool(info: i64) -> i32;
fn call_stack_pop_object(info: i64) -> i64;
fn call_stack_pop_vec2(info: i64) -> i64;
fn call_stack_pop_size(info: i64) -> i64;
fn call_stack_pop(info: i64) -> i32;
fn call_stack_front_i64(info: i64) -> i32;
fn call_stack_front_f64(info: i64) -> i32;
fn call_stack_front_str(info: i64) -> i32;
fn call_stack_front_bool(info: i64) -> i32;
fn call_stack_front_object(info: i64) -> i32;
fn call_stack_front_vec2(info: i64) -> i32;
fn call_stack_front_size(info: i64) -> i32;
fn dora_print(msg: i64);
fn dora_print_warning(msg: i64);
fn dora_print_error(msg: i64);
fn vec2_add(a: i64, b: i64) -> i64;
fn vec2_sub(a: i64, b: i64) -> i64;
fn vec2_mul(a: i64, b: i64) -> i64;
fn vec2_mul_float(a: i64, b: f32) -> i64;
fn vec2_div(a: i64, b: f32) -> i64;
fn vec2_distance(a: i64, b: i64) -> f32;
fn vec2_distance_squared(a: i64, b: i64) -> f32;
fn vec2_length(a: i64) -> f32;
fn vec2_angle(a: i64) -> f32;
fn vec2_normalize(a: i64) -> i64;
fn vec2_perp(a: i64) -> i64;
fn vec2_dot(a: i64, b: i64) -> f32;
fn vec2_clamp(a: i64, from: i64, to: i64) -> i64;
fn dora_emit(name: i64, stack: i64);
}
pub fn print(msg: &str) {
unsafe {
dora_print(from_string(msg));
}
}
pub fn print_warning(msg: &str) {
unsafe {
dora_print_warning(from_string(msg));
}
}
pub fn print_error(msg: &str) {
unsafe {
dora_print_error(from_string(msg));
}
}
pub fn emit(name: &str, stack: CallStack) {
unsafe {
dora_emit(from_string(name), stack.raw());
}
}
#[macro_export]
macro_rules! p {
() => {
dora_ssr::print("")
};
($($arg:tt)*) => {{
dora_ssr::print((format!($($arg)*)).as_str());
}};
}
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct Vec2 {
pub x: f32,
pub y: f32,
}
impl Vec2 {
pub(crate) fn from(value: i64) -> Vec2 {
unsafe { LightValue { value: value }.vec2 }
}
pub(crate) fn into_i64(&self) -> i64 {
unsafe { LightValue { vec2: *self }.value }
}
pub fn new(x: f32, y: f32) -> Vec2 {
Vec2 { x: x, y: y }
}
pub fn zero() -> Vec2 {
Vec2 { x: 0.0, y: 0.0 }
}
pub fn is_zero(&self) -> bool {
self.x == 0.0 && self.y == 0.0
}
pub fn distance(&self, other: &Vec2) -> f32 {
unsafe { vec2_distance(self.into_i64(), other.into_i64()) }
}
pub fn distance_squared(&self, other: &Vec2) -> f32 {
unsafe { vec2_distance_squared(self.into_i64(), other.into_i64()) }
}
pub fn length(&self) -> f32 {
unsafe { vec2_length(self.into_i64()) }
}
pub fn angle(&self) -> f32 {
unsafe { vec2_angle(self.into_i64()) }
}
pub fn normalize(&self) -> Vec2 {
Vec2::from(unsafe { vec2_normalize(self.into_i64()) })
}
pub fn perp(&self) -> Vec2 {
Vec2::from(unsafe { vec2_perp(self.into_i64()) })
}
pub fn dot(&self, other: &Vec2) -> f32 {
unsafe { vec2_dot(self.into_i64(), other.into_i64()) }
}
pub fn clamp(&self, from: &Vec2, to: &Vec2) -> Vec2 {
Vec2::from(unsafe { vec2_clamp(self.into_i64(), from.into_i64(), to.into_i64()) })
}
}
impl std::ops::Add for Vec2 {
type Output = Vec2;
fn add(self, other: Vec2) -> Vec2 {
Vec2::from(unsafe { vec2_add(self.into_i64(), other.into_i64()) })
}
}
impl std::ops::Sub for Vec2 {
type Output = Vec2;
fn sub(self, other: Vec2) -> Vec2 {
Vec2::from(unsafe { vec2_sub(self.into_i64(), other.into_i64()) })
}
}
impl std::ops::Mul for Vec2 {
type Output = Vec2;
fn mul(self, other: Vec2) -> Vec2 {
Vec2::from(unsafe { vec2_mul(self.into_i64(), other.into_i64()) })
}
}
impl std::ops::Mul<f32> for Vec2 {
type Output = Vec2;
fn mul(self, other: f32) -> Vec2 {
Vec2::from(unsafe { vec2_mul_float(self.into_i64(), other) })
}
}
impl std::ops::Div<f32> for Vec2 {
type Output = Vec2;
fn div(self, other: f32) -> Vec2 {
Vec2::from(unsafe { vec2_div(self.into_i64(), other) })
}
}
#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
pub struct Size {
pub width: f32,
pub height: f32,
}
impl Size {
pub fn new(width: f32, height: f32) -> Size {
Size { width: width, height: height }
}
pub fn zero() -> Size {
Size { width: 0.0, height: 0.0 }
}
pub fn is_zero(&self) -> bool {
self.width == 0.0 && self.height == 0.0
}
pub(crate) fn from(value: i64) -> Size {
unsafe { LightValue { value: value }.size }
}
pub(crate) fn into_i64(&self) -> i64 {
unsafe { LightValue { size: *self }.value }
}
}
#[repr(C)]
union LightValue {
vec2: Vec2,
size: Size,
value: i64,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Color {
pub b: u8,
pub g: u8,
pub r: u8,
pub a: u8,
}
#[repr(C)]
union ColorValue {
color: Color,
value: i32,
}
impl Color {
pub const WHITE: Color = Color { r: 255, g: 255, b: 255, a: 255 };
pub const BLACK: Color = Color { r: 0, g: 0, b: 0, a: 255 };
pub const TRANSPARENT: Color = Color { r: 0, g: 0, b: 0, a: 0 };
pub fn new(argb: u32) -> Color {
let a = argb >> 24;
let r = (argb & 0x00ff0000) >> 16;
let g = (argb & 0x0000ff00) >> 8;
let b = argb & 0x000000ff;
Color { r: r as u8, g: g as u8, b: b as u8, a: a as u8 }
}
pub fn from(argb: i32) -> Color {
unsafe { ColorValue { value: argb }.color }
}
pub fn to_argb(&self) -> u32 {
(self.a as u32) << 24 | (self.r as u32) << 16 | (self.g as u32) << 8 | self.b as u32
}
pub fn to_color3(&self) -> Color3 {
Color3 { r: self.r, g: self.g, b: self.b }
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct Color3 {
pub b: u8,
pub g: u8,
pub r: u8,
}
#[repr(C)]
#[derive(Clone, Copy)]
struct Color3a {
color3: Color3,
a: u8,
}
#[repr(C)]
union Color3Value {
color3a: Color3a,
value: i32,
}
impl Color3 {
pub const WHITE: Color3 = Color3 { r: 255, g: 255, b: 255 };
pub const BLACK: Color3 = Color3 { r: 0, g: 0, b: 0 };
pub fn new(rgb: u32) -> Color3 {
let r = (rgb & 0x00ff0000) >> 16;
let g = (rgb & 0x0000ff00) >> 8;
let b = rgb & 0x000000ff;
Color3 { r: r as u8, g: g as u8, b: b as u8 }
}
pub fn from(rgb: i32) -> Color3 {
unsafe { Color3Value { value: rgb }.color3a.color3 }
}
pub fn to_rgb(&self) -> u32 {
(self.r as u32) << 16 | (self.g as u32) << 8 | self.b as u32
}
}
fn to_string(str: i64) -> String {
unsafe {
let len = str_len(str) as usize;
let mut vec = Vec::with_capacity(len as usize);
vec.resize(len, 0);
let data = vec.as_mut_ptr() as *mut c_void;
str_read(data, str);
str_release(str);
return String::from_utf8(vec).unwrap();
}
}
fn from_string(s: &str) -> i64 {
unsafe {
let len = s.len() as i32;
let ptr = s.as_ptr();
let new_str = str_new(len);
str_write(new_str, ptr as *const c_void);
return new_str;
}
}
pub(crate) trait IBuf {
fn to_buf(&self) -> i64;
}
impl IBuf for Vec<i32> {
fn to_buf(&self) -> i64 {
unsafe {
let len = self.len() as i32;
let ptr = self.as_ptr();
let new_vec = buf_new_i32(len);
buf_write(new_vec, ptr as *const c_void);
return new_vec;
}
}
}
impl IBuf for Vec<i64> {
fn to_buf(&self) -> i64 {
unsafe {
let len = self.len() as i32;
let ptr = self.as_ptr();
let new_vec = buf_new_i64(len);
buf_write(new_vec, ptr as *const c_void);
return new_vec;
}
}
}
impl IBuf for Vec<f32> {
fn to_buf(&self) -> i64 {
unsafe {
let len = self.len() as i32;
let ptr = self.as_ptr();
let new_vec = buf_new_f32(len);
buf_write(new_vec, ptr as *const c_void);
return new_vec;
}
}
}
impl IBuf for Vec<f64> {
fn to_buf(&self) -> i64 {
unsafe {
let len = self.len() as i32;
let ptr = self.as_ptr();
let new_vec = buf_new_f64(len);
buf_write(new_vec, ptr as *const c_void);
return new_vec;
}
}
}
pub(crate) struct Vector;
impl Vector {
pub fn to_num<T>(v: i64) -> Vec<T>
where
T: Clone + Default,
{
unsafe {
let len = buf_len(v) as usize;
let mut vec: Vec<T> = Vec::with_capacity(len as usize);
vec.resize(len, Default::default());
let data = vec.as_mut_ptr() as *mut c_void;
buf_read(data, v);
buf_release(v);
return vec;
}
}
pub fn to_str(v: i64) -> Vec<String> {
unsafe {
let len = buf_len(v) as usize;
let mut vec: Vec<i64> = Vec::with_capacity(len as usize);
vec.resize(len, Default::default());
let data = vec.as_mut_ptr() as *mut c_void;
buf_read(data, v);
let mut strs = Vec::with_capacity(vec.len());
for i in 0..vec.len() {
strs.push(to_string(vec[i]));
}
buf_release(v);
strs
}
}
pub fn from_num<T: IBuf>(s: &T) -> i64 {
return s.to_buf();
}
pub fn from_str(s: &Vec<&str>) -> i64 {
unsafe {
let len = s.len() as i32;
let mut strs: Vec<i64> = Vec::with_capacity(s.len());
for i in 0..s.len() {
strs.push(from_string(s[i]));
}
let ptr = strs.as_ptr();
let new_vec = buf_new_i64(len);
buf_write(new_vec, ptr as *const c_void);
return new_vec;
}
}
pub fn from_vec2(s: &Vec<Vec2>) -> i64 {
unsafe {
let len = s.len() as i32;
let mut vs: Vec<i64> = Vec::with_capacity(s.len());
for i in 0..s.len() {
vs.push(LightValue { vec2: s[i] }.value);
}
let ptr = vs.as_ptr();
let new_vec = buf_new_i64(len);
buf_write(new_vec, ptr as *const c_void);
return new_vec;
}
}
pub fn from_vertex_color(s: &Vec<VertexColor>) -> i64 {
unsafe {
let len = s.len() as i32;
let mut vs: Vec<i64> = Vec::with_capacity(s.len());
for i in 0..s.len() {
vs.push(s[i].raw());
}
let ptr = vs.as_ptr();
let new_vec = buf_new_i64(len);
buf_write(new_vec, ptr as *const c_void);
return new_vec;
}
}
pub fn from_action_def(s: &Vec<ActionDef>) -> i64 {
unsafe {
let len = s.len() as i32;
let mut vs: Vec<i64> = Vec::with_capacity(s.len());
for i in 0..s.len() {
vs.push(s[i].raw());
}
let ptr = vs.as_ptr();
let new_vec = buf_new_i64(len);
buf_write(new_vec, ptr as *const c_void);
return new_vec;
}
}
pub fn from_btree(s: &Vec<platformer::behavior::Tree>) -> i64 {
unsafe {
let len = s.len() as i32;
let mut vs: Vec<i64> = Vec::with_capacity(s.len());
for i in 0..s.len() {
vs.push(s[i].raw());
}
let ptr = vs.as_ptr();
let new_vec = buf_new_i64(len);
buf_write(new_vec, ptr as *const c_void);
return new_vec;
}
}
pub fn from_dtree(s: &Vec<platformer::decision::Tree>) -> i64 {
unsafe {
let len = s.len() as i32;
let mut vs: Vec<i64> = Vec::with_capacity(s.len());
for i in 0..s.len() {
vs.push(s[i].raw());
}
let ptr = vs.as_ptr();
let new_vec = buf_new_i64(len);
buf_write(new_vec, ptr as *const c_void);
return new_vec;
}
}
}
fn into_object(raw: i64) -> Option<Box<dyn IObject>> {
let mut converted: Option<Box<dyn IObject>> = None;
OBJECT_MAP.with(|map| converted = map[unsafe { object_get_type(raw) } as usize].unwrap()(raw));
converted
}
fn new_object(raw: i64) -> Option<Box<dyn IObject>> {
unsafe {
object_retain(raw);
}
let mut converted: Option<Box<dyn IObject>> = None;
OBJECT_MAP.with(|map| converted = map[unsafe { object_get_type(raw) } as usize].unwrap()(raw));
converted
}
fn push_function(func: Box<dyn FnMut()>) -> i32 {
#[cfg(target_arch = "wasm32")]
let flag = 0x01000000;
#[cfg(not(target_arch = "wasm32"))]
let flag = 0x00000000;
let mut ret_func_id = -1;
FUNC_MAP.with_borrow_mut(|map| {
if map.len() >= 0xffffff {
panic!("too many functions!");
}
FUNC_AVAILABLE.with_borrow_mut(|available| {
if let Some(func_id) = available.pop() {
map[func_id as usize] = func;
ret_func_id = func_id | flag;
} else {
map.push(func);
ret_func_id = (map.len() - 1) as i32 | flag
}
})
});
ret_func_id
}
#[no_mangle]
pub extern "C" fn dora_wasm_version() -> i32 {
const MAJOR: &str = env!("CARGO_PKG_VERSION_MAJOR");
const MINOR: &str = env!("CARGO_PKG_VERSION_MINOR");
const PATCH: &str = env!("CARGO_PKG_VERSION_PATCH");
(MAJOR.parse::<i32>().unwrap() << 16)
| (MINOR.parse::<i32>().unwrap() << 8)
| PATCH.parse::<i32>().unwrap()
}
#[no_mangle]
pub extern "C" fn call_function(func_id: i32) {
let real_id = func_id & 0x00ffffff;
let mut func: *mut Box<dyn FnMut()> = std::ptr::null_mut();
FUNC_MAP.with_borrow_mut(|map| {
func = &mut map[real_id as usize];
});
unsafe {
(*func)();
}
}
fn dummy_func() {
panic!("the dummy function should not be called.");
}
#[no_mangle]
pub extern "C" fn deref_function(func_id: i32) {
let real_id = func_id & 0x00ffffff;
FUNC_MAP.with_borrow_mut(|map| {
map[real_id as usize] = Box::new(dummy_func);
FUNC_AVAILABLE.with_borrow_mut(|available| {
available.push(real_id);
});
});
}
pub trait IObject {
fn raw(&self) -> i64;
fn obj(&self) -> &dyn IObject;
fn get_id(&self) -> i32 {
unsafe { object_get_id(self.raw()) }
}
fn as_any(&self) -> &dyn Any;
}
pub struct Object {
raw: i64,
}
impl IObject for Object {
fn raw(&self) -> i64 {
self.raw
}
fn obj(&self) -> &dyn IObject {
self
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
}
impl Drop for Object {
fn drop(&mut self) {
unsafe {
crate::dora::object_release(self.raw);
}
}
}
impl Clone for Object {
fn clone(&self) -> Object {
unsafe {
crate::dora::object_retain(self.raw);
}
Object { raw: self.raw }
}
}
impl Object {
pub(crate) fn from(raw: i64) -> Option<Object> {
match raw {
0 => None,
_ => Some(Object { raw: raw }),
}
}
}
pub fn cast<T: Clone + 'static>(obj: &dyn IObject) -> Option<T> {
Some(new_object(obj.raw())?.as_any().downcast_ref::<T>()?.clone())
}
pub struct CallStack {
raw: i64,
}
pub enum DoraValue<'a> {
I32(i32),
I64(i64),
F32(f32),
F64(f64),
Bool(bool),
Str(&'a str),
Object(&'a dyn IObject),
Vec2(Vec2),
Size(Size),
}
pub trait IntoValue<'a> {
fn dora_val(self) -> DoraValue<'a>;
fn val(self) -> Value;
}
impl<'a> DoraValue<'a> {
pub fn push(self, info: &mut CallStack) {
match self {
DoraValue::I32(x) => info.push_i32(x),
DoraValue::I64(x) => info.push_i64(x),
DoraValue::F32(x) => info.push_f32(x),
DoraValue::F64(x) => info.push_f64(x),
DoraValue::Bool(x) => info.push_bool(x),
DoraValue::Str(x) => info.push_str(x),
DoraValue::Object(x) => info.push_object(x),
DoraValue::Vec2(x) => info.push_vec2(&x),
DoraValue::Size(x) => info.push_size(&x),
}
}
}
impl<'a> IntoValue<'a> for i32 {
fn dora_val(self) -> DoraValue<'a> {
DoraValue::I32(self)
}
fn val(self) -> Value {
unsafe { Value { raw: value_create_i64(self as i64) } }
}
}
impl<'a> IntoValue<'a> for i64 {
fn dora_val(self) -> DoraValue<'a> {
DoraValue::I64(self)
}
fn val(self) -> Value {
unsafe { Value { raw: value_create_i64(self) } }
}
}
impl<'a> IntoValue<'a> for f32 {
fn dora_val(self) -> DoraValue<'a> {
DoraValue::F32(self)
}
fn val(self) -> Value {
unsafe { Value { raw: value_create_f64(self as f64) } }
}
}
impl<'a> IntoValue<'a> for f64 {
fn dora_val(self) -> DoraValue<'a> {
DoraValue::F64(self)
}
fn val(self) -> Value {
unsafe { Value { raw: value_create_f64(self) } }
}
}
impl<'a> IntoValue<'a> for bool {
fn dora_val(self) -> DoraValue<'a> {
DoraValue::Bool(self)
}
fn val(self) -> Value {
unsafe { Value { raw: value_create_bool(if self { 1 } else { 0 }) } }
}
}
impl<'a> IntoValue<'a> for &'a str {
fn dora_val(self) -> DoraValue<'a> {
DoraValue::Str(self)
}
fn val(self) -> Value {
unsafe { Value { raw: value_create_str(from_string(self)) } }
}
}
impl<'a> IntoValue<'a> for &'a dyn IObject {
fn dora_val(self) -> DoraValue<'a> {
DoraValue::Object(self)
}
fn val(self) -> Value {
unsafe { Value { raw: value_create_object(self.raw()) } }
}
}
impl<'a> IntoValue<'a> for Vec2 {
fn dora_val(self) -> DoraValue<'a> {
DoraValue::Vec2(self)
}
fn val(self) -> Value {
unsafe { Value { raw: value_create_vec2(self.into_i64()) } }
}
}
impl<'a> IntoValue<'a> for Size {
fn dora_val(self) -> DoraValue<'a> {
DoraValue::Size(self)
}
fn val(self) -> Value {
unsafe { Value { raw: value_create_size(self.into_i64()) } }
}
}
#[macro_export]
macro_rules! args {
( $( $x:expr ),* ) => {
{
let mut stack = dora_ssr::CallStack::new();
$(
dora_ssr::Value::new($x).push(&mut stack);
)*
stack
}
};
}
#[macro_export]
macro_rules! dora_object {
($name: ident) => {
paste::paste! {
impl IObject for $name {
fn raw(&self) -> i64 { self.raw }
fn obj(&self) -> &dyn IObject { self }
fn as_any(&self) -> &dyn std::any::Any { self }
}
impl Drop for $name {
fn drop(&mut self) { unsafe { crate::dora::object_release(self.raw); } }
}
impl Clone for $name {
fn clone(&self) -> $name {
unsafe { crate::dora::object_retain(self.raw); }
$name { raw: self.raw }
}
}
impl $name {
#[allow(dead_code)]
pub(crate) fn from(raw: i64) -> Option<$name> {
match raw {
0 => None,
_ => Some($name { raw: raw })
}
}
}
}
};
}
pub struct Value {
raw: i64,
}
impl Value {
pub fn new<'a, A>(value: A) -> DoraValue<'a>
where
A: IntoValue<'a>,
{
value.dora_val()
}
fn from(raw: i64) -> Option<Value> {
match raw {
0 => None,
_ => Some(Value { raw: raw }),
}
}
pub fn raw(&self) -> i64 {
self.raw
}
pub fn into_i32(&self) -> Option<i32> {
unsafe {
if value_is_i64(self.raw) != 0 {
Some(value_into_i64(self.raw) as i32)
} else {
None
}
}
}
pub fn into_i64(&self) -> Option<i64> {
unsafe {
if value_is_i64(self.raw) != 0 {
Some(value_into_i64(self.raw))
} else {
None
}
}
}
pub fn into_f32(&self) -> Option<f32> {
unsafe {
if value_is_f64(self.raw) != 0 {
Some(value_into_f64(self.raw) as f32)
} else {
None
}
}
}
pub fn into_f64(&self) -> Option<f64> {
unsafe {
if value_is_f64(self.raw) != 0 {
Some(value_into_f64(self.raw))
} else {
None
}
}
}
pub fn into_bool(&self) -> Option<bool> {
unsafe {
if value_is_bool(self.raw) != 0 {
Some(value_into_bool(self.raw) != 0)
} else {
None
}
}
}
pub fn into_str(&self) -> Option<String> {
unsafe {
if value_is_str(self.raw) != 0 {
Some(to_string(value_into_str(self.raw)))
} else {
None
}
}
}
pub fn into_object(&self) -> Option<Box<dyn IObject>> {
unsafe {
if value_is_object(self.raw) != 0 {
into_object(value_into_object(self.raw))
} else {
None
}
}
}
pub fn into_node(&self) -> Option<Node> {
Node::cast(self.into_object()?.as_ref())
}
pub fn into_camera(&self) -> Option<Camera> {
Camera::cast(self.into_object()?.as_ref())
}
pub fn into_playable(&self) -> Option<Playable> {
Playable::cast(self.into_object()?.as_ref())
}
pub fn into_physics_world(&self) -> Option<PhysicsWorld> {
PhysicsWorld::cast(self.into_object()?.as_ref())
}
pub fn into_body(&self) -> Option<Body> {
Body::cast(self.into_object()?.as_ref())
}
pub fn into_joint(&self) -> Option<Joint> {
Joint::cast(self.into_object()?.as_ref())
}
pub fn into_vec2(&self) -> Option<Vec2> {
unsafe {
if value_is_vec2(self.raw) != 0 {
Some(Vec2::from(value_into_vec2(self.raw)))
} else {
None
}
}
}
pub fn into_size(&self) -> Option<Size> {
unsafe {
if value_is_size(self.raw) != 0 {
Some(Size::from(value_into_size(self.raw)))
} else {
None
}
}
}
pub fn cast<T: Clone + 'static>(&self) -> Option<T> {
cast::<T>(self.into_object()?.as_ref())
}
}
impl Drop for Value {
fn drop(&mut self) {
unsafe {
value_release(self.raw);
}
}
}
impl CallStack {
fn raw(&self) -> i64 {
self.raw
}
pub fn new() -> CallStack {
CallStack { raw: unsafe { call_stack_create() } }
}
pub fn push_i32(&mut self, value: i32) {
unsafe {
call_stack_push_i64(self.raw, value as i64);
}
}
pub fn push_i64(&mut self, value: i64) {
unsafe {
call_stack_push_i64(self.raw, value);
}
}
pub fn push_f32(&mut self, value: f32) {
unsafe {
call_stack_push_f64(self.raw, value as f64);
}
}
pub fn push_f64(&mut self, value: f64) {
unsafe {
call_stack_push_f64(self.raw, value);
}
}
pub fn push_str(&mut self, value: &str) {
unsafe {
call_stack_push_str(self.raw, from_string(value));
}
}
pub fn push_bool(&mut self, value: bool) {
unsafe {
call_stack_push_bool(self.raw, if value { 1 } else { 0 });
}
}
pub fn push_object(&mut self, value: &dyn IObject) {
unsafe {
call_stack_push_object(self.raw, value.raw());
}
}
pub fn push_vec2(&mut self, value: &Vec2) {
unsafe {
call_stack_push_vec2(self.raw, value.into_i64());
}
}
pub fn push_size(&mut self, value: &Size) {
unsafe {
call_stack_push_size(self.raw, value.into_i64());
}
}
pub fn pop_i32(&mut self) -> Option<i32> {
unsafe {
if call_stack_front_i64(self.raw) != 0 {
Some(call_stack_pop_i64(self.raw) as i32)
} else {
None
}
}
}
pub fn pop_i64(&mut self) -> Option<i64> {
unsafe {
if call_stack_front_i64(self.raw) != 0 {
Some(call_stack_pop_i64(self.raw))
} else {
None
}
}
}
pub fn pop_f32(&mut self) -> Option<f32> {
unsafe {
if call_stack_front_f64(self.raw) != 0 {
Some(call_stack_pop_f64(self.raw) as f32)
} else {
None
}
}
}
pub fn pop_f64(&mut self) -> Option<f64> {
unsafe {
if call_stack_front_f64(self.raw) != 0 {
Some(call_stack_pop_f64(self.raw))
} else {
None
}
}
}
pub fn pop_str(&mut self) -> Option<String> {
unsafe {
if call_stack_front_str(self.raw) != 0 {
Some(to_string(call_stack_pop_str(self.raw)))
} else {
None
}
}
}
pub fn pop_bool(&mut self) -> Option<bool> {
unsafe {
if call_stack_front_bool(self.raw) != 0 {
Some(call_stack_pop_bool(self.raw) != 0)
} else {
None
}
}
}
pub fn pop_vec2(&mut self) -> Option<Vec2> {
unsafe {
if call_stack_front_vec2(self.raw) != 0 {
Some(Vec2::from(call_stack_pop_vec2(self.raw)))
} else {
None
}
}
}
pub fn pop_size(&mut self) -> Option<Size> {
unsafe {
if call_stack_front_size(self.raw) != 0 {
Some(Size::from(call_stack_pop_size(self.raw)))
} else {
None
}
}
}
pub fn pop_object(&mut self) -> Option<Box<dyn IObject>> {
unsafe {
if call_stack_front_object(self.raw) != 0 {
let raw = call_stack_pop_object(self.raw);
into_object(raw)
} else {
None
}
}
}
pub fn pop_into_node(&mut self) -> Option<Node> {
Node::cast(self.pop_object()?.as_ref())
}
pub fn pop_into_camera(&mut self) -> Option<Camera> {
Camera::cast(self.pop_object()?.as_ref())
}
pub fn pop_into_playable(&mut self) -> Option<Playable> {
Playable::cast(self.pop_object()?.as_ref())
}
pub fn pop_into_physics_world(&mut self) -> Option<PhysicsWorld> {
PhysicsWorld::cast(self.pop_object()?.as_ref())
}
pub fn pop_into_body(&mut self) -> Option<Body> {
Body::cast(self.pop_object()?.as_ref())
}
pub fn pop_into_joint(&mut self) -> Option<Joint> {
Joint::cast(self.pop_object()?.as_ref())
}
pub fn pop_cast<T: Clone + 'static>(&mut self) -> Option<T> {
cast::<T>(self.pop_object()?.as_ref())
}
pub fn pop(&mut self) -> bool {
if unsafe { call_stack_pop(self.raw) } == 0 {
return false;
}
true
}
}
impl Drop for CallStack {
fn drop(&mut self) {
unsafe {
call_stack_release(self.raw);
}
}
}
pub struct Slot {}
impl Slot {
pub const ACTION_END: &'static str = "Action";
pub const TAP_FILTER: &'static str = "TapFilter";
pub const TAP_BEGAN: &'static str = "TapBegan";
pub const TAP_ENDED: &'static str = "TapEnded";
pub const TAPPED: &'static str = "Tapped";
pub const TAP_MOVED: &'static str = "TapMoved";
pub const MOUSE_WHEEL: &'static str = "MouseWheel";
pub const GESTURE: &'static str = "Gesture";
pub const ENTER: &'static str = "Enter";
pub const EXIT: &'static str = "Exit";
pub const CLEANUP: &'static str = "Cleanup";
pub const KEY_DOWN: &'static str = "KeyDown";
pub const KEY_UP: &'static str = "KeyUp";
pub const KEY_PRESSED: &'static str = "KeyPressed";
pub const ATTACH_IME: &'static str = "AttachIME";
pub const DETACH_IME: &'static str = "DetachIME";
pub const TEXT_INPUT: &'static str = "TextInput";
pub const TEXT_EDITING: &'static str = "TextEditing";
pub const BUTTON_DOWN: &'static str = "ButtonDown";
pub const BUTTON_UP: &'static str = "ButtonUp";
pub const BUTTON_PRESSED: &'static str = "ButtonPressed";
pub const AXIS: &'static str = "Axis";
pub const ANIMATION_END: &'static str = "AnimationEnd";
pub const BODY_ENTER: &'static str = "BodyEnter";
pub const BODY_LEAVE: &'static str = "BodyLeave";
pub const CONTACT_START: &'static str = "ContactStart";
pub const CONTACT_END: &'static str = "ContactEnd";
pub const FINISHED: &'static str = "Finished";
pub const ALIGN_LAYOUT: &'static str = "AlignLayout";
pub const EFFEK_END: &'static str = "EffekEnd";
pub fn on_action_end<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*action*/ Action, /*node*/ Node) + 'static,
{
node.slot(
Slot::ACTION_END,
Box::new(move |stack| {
let (action, node) = match (stack.pop_cast::<Action>(), stack.pop_into_node()) {
(Some(action), Some(node)) => (action, node),
_ => return,
};
callback(action, node);
}),
);
}
pub fn on_tap_filter<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*touch*/ Touch) + 'static,
{
node.set_touch_enabled(true);
node.slot(
Slot::TAP_FILTER,
Box::new(move |stack| {
let touch = match stack.pop_cast::<Touch>() {
Some(touch) => touch,
None => return,
};
callback(touch);
}),
);
}
pub fn on_tap_began<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*touch*/ Touch) + 'static,
{
node.set_touch_enabled(true);
node.slot(
Slot::TAP_BEGAN,
Box::new(move |stack| {
let touch = match stack.pop_cast::<Touch>() {
Some(touch) => touch,
None => return,
};
callback(touch);
}),
);
}
pub fn on_tap_ended<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*touch*/ Touch) + 'static,
{
node.set_touch_enabled(true);
node.slot(
Slot::TAP_ENDED,
Box::new(move |stack| {
let touch = match stack.pop_cast::<Touch>() {
Some(touch) => touch,
None => return,
};
callback(touch);
}),
);
}
pub fn on_tapped<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*touch*/ Touch) + 'static,
{
node.set_touch_enabled(true);
node.slot(
Slot::TAPPED,
Box::new(move |stack| {
let touch = match stack.pop_cast::<Touch>() {
Some(touch) => touch,
None => return,
};
callback(touch);
}),
);
}
pub fn on_tap_moved<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*touch*/ Touch) + 'static,
{
node.set_touch_enabled(true);
node.slot(
Slot::TAP_MOVED,
Box::new(move |stack| {
let touch = match stack.pop_cast::<Touch>() {
Some(touch) => touch,
None => return,
};
callback(touch);
}),
);
}
pub fn on_mouse_wheel<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*delta*/ Vec2) + 'static,
{
node.set_touch_enabled(true);
node.slot(
Slot::MOUSE_WHEEL,
Box::new(move |stack| {
let delta = match stack.pop_vec2() {
Some(delta) => delta,
None => return,
};
callback(delta);
}),
);
}
pub fn on_gesture<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(
/*center*/ Vec2,
/*num_fingers*/ i32,
/*delta_dist*/ f32,
/*delta_angle*/ f32,
) + 'static,
{
node.set_touch_enabled(true);
node.slot(
Slot::GESTURE,
Box::new(move |stack| {
let (center, num_fingers, delta_dist, delta_angle) =
match (stack.pop_vec2(), stack.pop_i32(), stack.pop_f32(), stack.pop_f32()) {
(Some(center), Some(num_fingers), Some(delta_dist), Some(delta_angle)) => {
(center, num_fingers, delta_dist, delta_angle)
}
_ => return,
};
callback(center, num_fingers, delta_dist, delta_angle);
}),
);
}
pub fn on_enter<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut() + 'static,
{
node.slot(
Slot::ENTER,
Box::new(move |_| {
callback();
}),
);
}
pub fn on_exit<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut() + 'static,
{
node.slot(
Slot::EXIT,
Box::new(move |_| {
callback();
}),
);
}
pub fn on_cleanup<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut() + 'static,
{
node.slot(
Slot::CLEANUP,
Box::new(move |_| {
callback();
}),
);
}
pub fn on_key_down<F>(node: &mut dyn INode, key: KeyName, mut callback: F)
where
F: FnMut() + 'static,
{
node.set_keyboard_enabled(true);
node.slot(
Slot::KEY_DOWN,
Box::new(move |stack| {
let key_name = match stack.pop_str() {
Some(key_name) => key_name,
None => return,
};
if key.as_ref() == key_name {
callback();
}
}),
);
}
pub fn on_key_up<F>(node: &mut dyn INode, key: KeyName, mut callback: F)
where
F: FnMut() + 'static,
{
node.set_keyboard_enabled(true);
node.slot(
Slot::KEY_UP,
Box::new(move |stack| {
let key_name = match stack.pop_str() {
Some(key_name) => key_name,
None => return,
};
if key.as_ref() == key_name {
callback();
}
}),
);
}
pub fn on_key_pressed<F>(node: &mut dyn INode, key: KeyName, mut callback: F)
where
F: FnMut() + 'static,
{
node.set_keyboard_enabled(true);
node.slot(
Slot::KEY_PRESSED,
Box::new(move |stack| {
let key_name = match stack.pop_str() {
Some(key_name) => key_name,
None => return,
};
if key.as_ref() == key_name {
callback();
}
}),
);
}
pub fn on_attach_ime<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut() + 'static,
{
node.slot(
Slot::ATTACH_IME,
Box::new(move |_| {
callback();
}),
);
}
pub fn on_detach_ime<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut() + 'static,
{
node.slot(
Slot::DETACH_IME,
Box::new(move |_| {
callback();
}),
);
}
pub fn on_text_input<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*text*/ String) + 'static,
{
node.slot(
Slot::TEXT_INPUT,
Box::new(move |stack| {
let text = match stack.pop_str() {
Some(text) => text,
None => return,
};
callback(text);
}),
);
}
pub fn on_text_editing<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*text*/ String, /*start_pos*/ i32) + 'static,
{
node.slot(
Slot::TEXT_EDITING,
Box::new(move |stack| {
let (text, start_pos) = match (stack.pop_str(), stack.pop_i32()) {
(Some(text), Some(start_pos)) => (text, start_pos),
_ => return,
};
callback(text, start_pos);
}),
);
}
pub fn on_button_down<F>(node: &mut dyn INode, button: ButtonName, mut callback: F)
where
F: FnMut(/*controller_id*/ i32) + 'static,
{
node.set_controller_enabled(true);
node.slot(
Slot::BUTTON_DOWN,
Box::new(move |stack| {
let (controller_id, button_name) = match (stack.pop_i32(), stack.pop_str()) {
(Some(controller_id), Some(button_name)) => (controller_id, button_name),
_ => return,
};
if button.as_ref() == button_name {
callback(controller_id);
}
}),
);
}
pub fn on_button_up<F>(node: &mut dyn INode, button: ButtonName, mut callback: F)
where
F: FnMut(/*controller_id*/ i32) + 'static,
{
node.set_controller_enabled(true);
node.slot(
Slot::BUTTON_UP,
Box::new(move |stack| {
let (controller_id, button_name) = match (stack.pop_i32(), stack.pop_str()) {
(Some(controller_id), Some(button_name)) => (controller_id, button_name),
_ => return,
};
if button.as_ref() == button_name {
callback(controller_id);
}
}),
);
}
pub fn on_button_pressed<F>(node: &mut dyn INode, button: ButtonName, mut callback: F)
where
F: FnMut(/*controller_id*/ i32) + 'static,
{
node.set_controller_enabled(true);
node.slot(
Slot::BUTTON_PRESSED,
Box::new(move |stack| {
let (controller_id, button_name) = match (stack.pop_i32(), stack.pop_str()) {
(Some(controller_id), Some(button_name)) => (controller_id, button_name),
_ => return,
};
if button.as_ref() == button_name {
callback(controller_id);
}
}),
);
}
pub fn on_axis<F>(node: &mut dyn INode, axis: AxisName, mut callback: F)
where
F: FnMut(/*controller_id*/ i32, /*axis_value*/ f32) + 'static,
{
node.set_controller_enabled(true);
node.slot(
Slot::AXIS,
Box::new(move |stack| {
let (controller_id, axis_name, axis_value) =
match (stack.pop_i32(), stack.pop_str(), stack.pop_f32()) {
(Some(controller_id), Some(axis_name), Some(axis_value)) => {
(controller_id, axis_name, axis_value)
}
_ => return,
};
if axis.as_ref() == axis_name {
callback(controller_id, axis_value);
}
}),
);
}
pub fn on_animation_end<F>(node: &mut dyn IPlayable, mut callback: F)
where
F: FnMut(/*animation_name*/ String, /*target*/ Playable) + 'static,
{
node.slot(
Slot::ANIMATION_END,
Box::new(move |stack| {
let (animation_name, playable) = match (stack.pop_str(), stack.pop_into_playable())
{
(Some(animation_name), Some(playable)) => (animation_name, playable),
_ => return,
};
callback(animation_name, playable);
}),
);
}
pub fn on_body_enter<F>(node: &mut dyn IBody, mut callback: F)
where
F: FnMut(/*other*/ Body, /*sensor_tag*/ i32) + 'static,
{
node.slot(
Slot::BODY_ENTER,
Box::new(move |stack| {
let (other, sensor_tag) = match (stack.pop_into_body(), stack.pop_i32()) {
(Some(other), Some(sensor_tag)) => (other, sensor_tag),
_ => return,
};
callback(other, sensor_tag);
}),
);
}
pub fn on_body_leave<F>(node: &mut dyn IBody, mut callback: F)
where
F: FnMut(/*other*/ Body, /*sensor_tag*/ i32) + 'static,
{
node.slot(
Slot::BODY_LEAVE,
Box::new(move |stack| {
let (other, sensor_tag) = match (stack.pop_into_body(), stack.pop_i32()) {
(Some(other), Some(sensor_tag)) => (other, sensor_tag),
_ => return,
};
callback(other, sensor_tag);
}),
);
}
pub fn on_contact_start<F>(node: &mut dyn IBody, mut callback: F)
where
F: FnMut(
/*other*/ Body,
/*point*/ Vec2,
/*normal*/ Vec2,
/*enabled*/ bool,
) + 'static,
{
node.set_receiving_contact(true);
node.slot(
Slot::CONTACT_START,
Box::new(move |stack| {
let (other, point, normal, enabled) = match (
stack.pop_into_body(),
stack.pop_vec2(),
stack.pop_vec2(),
stack.pop_bool(),
) {
(Some(other), Some(point), Some(normal), Some(enabled)) => {
(other, point, normal, enabled)
}
_ => return,
};
callback(other, point, normal, enabled);
}),
);
}
pub fn on_contact_end<F>(node: &mut dyn IBody, mut callback: F)
where
F: FnMut(/*other*/ Body, /*point*/ Vec2, /*normal*/ Vec2) + 'static,
{
node.set_receiving_contact(true);
node.slot(
Slot::CONTACT_END,
Box::new(move |stack| {
let (other, point, normal) =
match (stack.pop_into_body(), stack.pop_vec2(), stack.pop_vec2()) {
(Some(other), Some(point), Some(normal)) => (other, point, normal),
_ => return,
};
callback(other, point, normal);
}),
);
}
pub fn on_finished<F>(node: &mut Particle, mut callback: F)
where
F: FnMut() + 'static,
{
node.slot(
Slot::FINISHED,
Box::new(move |_| {
callback();
}),
);
}
pub fn on_align_layout<F>(node: &mut AlignNode, mut callback: F)
where
F: FnMut(/*width*/ f32, /*height*/ f32) + 'static,
{
node.slot(
Slot::ALIGN_LAYOUT,
Box::new(move |stack| {
let (width, height) = match (stack.pop_f32(), stack.pop_f32()) {
(Some(width), Some(height)) => (width, height),
_ => return,
};
callback(width, height);
}),
);
}
pub fn on_effek_end<F>(node: &mut EffekNode, mut callback: F)
where
F: FnMut(/*handle*/ i32) + 'static,
{
node.slot(
Slot::EFFEK_END,
Box::new(move |stack| {
let handle = match stack.pop_i32() {
Some(handle) => handle,
None => return,
};
callback(handle);
}),
);
}
}
pub struct GSlot {}
impl GSlot {
pub const APP_EVENT: &'static str = "AppEvent";
pub const APP_CHANGE: &'static str = "AppChange";
pub const APP_WS: &'static str = "AppWS";
pub fn on_app_event<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*event_type*/ String) + 'static,
{
node.gslot(
GSlot::APP_EVENT,
Box::new(move |stack| {
let event_type = match stack.pop_str() {
Some(event_type) => event_type,
None => return,
};
callback(event_type);
}),
);
}
pub fn on_app_change<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*setting_name*/ String) + 'static,
{
node.gslot(
GSlot::APP_CHANGE,
Box::new(move |stack| {
let setting_name = match stack.pop_str() {
Some(setting_name) => setting_name,
None => return,
};
callback(setting_name);
}),
);
}
pub fn on_app_ws<F>(node: &mut dyn INode, mut callback: F)
where
F: FnMut(/*event_type*/ String, /*msg*/ String) + 'static,
{
node.gslot(
GSlot::APP_WS,
Box::new(move |stack| {
let (event_type, msg) = match (stack.pop_str(), stack.pop_str()) {
(Some(event_type), Some(msg)) => (event_type, msg),
_ => return,
};
callback(event_type, msg);
}),
);
}
}
extern "C" {
fn content_load(filename: i64) -> i64;
}
impl Content {
pub fn load(filename: &str) -> Option<String> {
let result = unsafe { content_load(from_string(filename)) };
if result > 0 {
Some(to_string(result))
} else {
None
}
}
}
extern "C" {
fn array_set(array: i64, index: i32, item: i64) -> i32;
fn array_get(array: i64, index: i32) -> i64;
fn array_first(array: i64) -> i64;
fn array_last(array: i64) -> i64;
fn array_random_object(array: i64) -> i64;
fn array_add(array: i64, item: i64);
fn array_insert(array: i64, index: i32, item: i64);
fn array_contains(array: i64, item: i64) -> i32;
fn array_index(array: i64, item: i64) -> i32;
fn array_remove_last(array: i64) -> i64;
fn array_fast_remove(array: i64, item: i64) -> i32;
}
impl Array {
pub fn set<'a, T>(&mut self, index: i32, v: T)
where
T: IntoValue<'a>,
{
if unsafe { array_set(self.raw(), index, v.val().raw()) == 0 } {
panic!("Out of bounds, expecting [0, {}), got {}", self.get_count(), index);
}
}
pub fn get(&self, index: i32) -> Option<Value> {
Value::from(unsafe { array_get(self.raw(), index) })
}
pub fn first(&self) -> Option<Value> {
Value::from(unsafe { array_first(self.raw()) })
}
pub fn last(&self) -> Option<Value> {
Value::from(unsafe { array_last(self.raw()) })
}
pub fn random_object(&self) -> Option<Value> {
Value::from(unsafe { array_random_object(self.raw()) })
}
pub fn add<'a, T>(&mut self, v: T) -> &mut Self
where
T: IntoValue<'a>,
{
unsafe {
array_add(self.raw(), v.val().raw());
}
self
}
pub fn insert<'a, T>(&mut self, index: i32, v: T)
where
T: IntoValue<'a>,
{
unsafe {
array_insert(self.raw(), index, v.val().raw());
}
}
pub fn contains<'a, T>(&self, v: T) -> bool
where
T: IntoValue<'a>,
{
unsafe { array_contains(self.raw(), v.val().raw()) != 0 }
}
pub fn index<'a, T>(&self, v: T) -> i32
where
T: IntoValue<'a>,
{
unsafe { array_index(self.raw(), v.val().raw()) }
}
pub fn remove_last(&mut self) -> Option<Value> {
Value::from(unsafe { array_remove_last(self.raw()) })
}
pub fn fast_remove<'a, T>(&mut self, v: T) -> bool
where
T: IntoValue<'a>,
{
unsafe { array_fast_remove(self.raw(), v.val().raw()) != 0 }
}
}
extern "C" {
fn dictionary_set(dict: i64, key: i64, value: i64);
fn dictionary_get(dict: i64, key: i64) -> i64;
}
impl Dictionary {
pub fn set<'a, T>(&mut self, key: &str, v: T)
where
T: IntoValue<'a>,
{
unsafe {
dictionary_set(self.raw(), from_string(key), v.val().raw());
}
}
pub fn get(&self, key: &str) -> Option<Value> {
Value::from(unsafe { dictionary_get(self.raw(), from_string(key)) })
}
}
extern "C" {
fn entity_set(e: i64, k: i64, v: i64);
fn entity_get(e: i64, k: i64) -> i64;
fn entity_get_old(e: i64, k: i64) -> i64;
}
impl Entity {
pub fn set<'a, T>(&mut self, key: &str, value: T)
where
T: IntoValue<'a>,
{
unsafe {
entity_set(self.raw(), from_string(key), value.val().raw());
}
}
pub fn get(&self, key: &str) -> Option<Value> {
Value::from(unsafe { entity_get(self.raw(), from_string(key)) })
}
pub fn get_old(&self, key: &str) -> Option<Value> {
Value::from(unsafe { entity_get_old(self.raw(), from_string(key)) })
}
}
extern "C" {
fn group_watch(group: i64, func: i32, stack: i64);
}
impl Group {
pub fn watch(&mut self, mut callback: Box<dyn FnMut(&mut CallStack) -> bool>) -> &mut Group {
let mut stack = CallStack::new();
let stack_raw = stack.raw();
let func_id = push_function(Box::new(move || {
let result = callback(&mut stack);
stack.push_bool(result);
}));
unsafe {
group_watch(self.raw(), func_id, stack_raw);
}
self
}
pub fn each(&self, visitor: Box<dyn FnMut(&Entity) -> bool>) -> bool {
match self.find(visitor) {
Some(_) => true,
None => false,
}
}
}
extern "C" {
fn observer_watch(observer: i64, func: i32, stack: i64);
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum EntityEvent {
Add = 1,
Change = 2,
AddOrChange = 3,
Remove = 4,
}
impl Observer {
pub fn watch(&mut self, mut callback: Box<dyn FnMut(&mut CallStack) -> bool>) -> &mut Observer {
let mut stack = CallStack::new();
let stack_raw = stack.raw();
let func_id = push_function(Box::new(move || {
let result = callback(&mut stack);
stack.push_bool(result);
}));
unsafe {
observer_watch(self.raw(), func_id, stack_raw);
}
self
}
}
#[cfg(not(target_arch = "wasm32"))]
extern "C" {
fn director_get_scheduler() -> i64;
fn director_get_post_scheduler() -> i64;
}
#[cfg(target_arch = "wasm32")]
extern "C" {
fn director_get_wasm_scheduler() -> i64;
fn director_get_post_wasm_scheduler() -> i64;
}
impl Director {
pub fn get_scheduler() -> Scheduler {
#[cfg(target_arch = "wasm32")]
{
Scheduler::from(unsafe { director_get_wasm_scheduler() }).unwrap()
}
#[cfg(not(target_arch = "wasm32"))]
{
Scheduler::from(unsafe { director_get_scheduler() }).unwrap()
}
}
pub fn get_post_scheduler() -> Scheduler {
#[cfg(target_arch = "wasm32")]
{
Scheduler::from(unsafe { director_get_post_wasm_scheduler() }).unwrap()
}
#[cfg(not(target_arch = "wasm32"))]
{
Scheduler::from(unsafe { director_get_post_scheduler() }).unwrap()
}
}
}
impl Node {
pub fn cast(obj: &dyn IObject) -> Option<Node> {
let node = Node::from(unsafe { object_to_node(obj.raw()) });
if node.is_some() {
unsafe {
object_retain(obj.raw());
}
}
node
}
}
impl Camera {
pub fn cast(obj: &dyn IObject) -> Option<Camera> {
let camera = Camera::from(unsafe { object_to_camera(obj.raw()) });
if camera.is_some() {
unsafe {
object_retain(obj.raw());
}
}
camera
}
}
impl Playable {
pub fn cast(obj: &dyn IObject) -> Option<Playable> {
let playable = Playable::from(unsafe { object_to_playable(obj.raw()) });
if playable.is_some() {
unsafe {
object_retain(obj.raw());
}
}
playable
}
}
impl Body {
pub fn cast(obj: &dyn IObject) -> Option<Body> {
let body = Body::from(unsafe { object_to_body(obj.raw()) });
if body.is_some() {
unsafe {
object_retain(obj.raw());
}
}
body
}
}
impl Joint {
pub fn cast(obj: &dyn IObject) -> Option<Joint> {
let joint = Joint::from(unsafe { object_to_joint(obj.raw()) });
if joint.is_some() {
unsafe {
object_retain(obj.raw());
}
}
joint
}
}
impl PhysicsWorld {
pub fn cast(obj: &dyn IObject) -> Option<PhysicsWorld> {
let physics_world = PhysicsWorld::from(unsafe { object_to_physics_world(obj.raw()) });
if physics_world.is_some() {
unsafe {
object_retain(obj.raw());
}
}
physics_world
}
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TextureWrap {
None = 0,
Mirror = 1,
Clamp = 2,
Border = 3,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TextureFilter {
None = 0,
Point = 1,
Anisotropic = 2,
}
#[repr(u64)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BFunc {
Zero = 0x0000000000001000,
One = 0x0000000000002000,
SrcColor = 0x0000000000003000,
InvSrcColor = 0x0000000000004000,
SrcAlpha = 0x0000000000005000,
InvSrcAlpha = 0x0000000000006000,
DstAlpha = 0x0000000000007000,
InvDstAlpha = 0x0000000000008000,
DstColor = 0x0000000000009000,
InvDstColor = 0x000000000000a000,
}
pub struct BlendFunc {
value: u64,
}
impl BlendFunc {
pub fn new_seperate(
src_rgb: BFunc,
dst_rgb: BFunc,
src_alpha: BFunc,
dst_alpha: BFunc,
) -> Self {
BlendFunc {
value: (src_rgb as u64
| (dst_rgb as u64) << 4
| src_alpha as u64
| (dst_alpha as u64) << 4)
<< 8,
}
}
pub fn new(src: BFunc, dst: BFunc) -> Self {
BlendFunc::new_seperate(src, dst, src, dst)
}
pub fn from(value: i64) -> Self {
BlendFunc { value: value as u64 }
}
pub(crate) fn to_value(&self) -> i64 {
self.value as i64
}
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum EaseType {
Linear = 0,
InQuad = 1,
OutQuad = 2,
InOutQuad = 3,
InCubic = 4,
OutCubic = 5,
InOutCubic = 6,
InQuart = 7,
OutQuart = 8,
InOutQuart = 9,
InQuint = 10,
OutQuint = 11,
InOutQuint = 12,
InSine = 13,
OutSine = 14,
InOutSine = 15,
InExpo = 16,
OutExpo = 17,
InOutExpo = 18,
InCirc = 19,
OutCirc = 20,
InOutCirc = 21,
InElastic = 22,
OutElastic = 23,
InOutElastic = 24,
InBack = 25,
OutBack = 26,
InOutBack = 27,
InBounce = 28,
OutBounce = 29,
InOutBounce = 30,
OutInQuad = 31,
OutInCubic = 32,
OutInQuart = 33,
OutInQuint = 34,
OutInSine = 35,
OutInExpo = 36,
OutInCirc = 37,
OutInElastic = 38,
OutInBack = 39,
OutInBounce = 40,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Property {
X = 0,
Y = 1,
Z = 2,
Angle = 3,
AngleX = 4,
AngleY = 5,
ScaleX = 6,
ScaleY = 7,
SkewX = 8,
SkewY = 9,
Width = 10,
Height = 11,
AnchorX = 12,
AnchorY = 13,
Opacity = 14,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TextAlign {
Left = 0,
Center = 1,
Right = 2,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BodyType {
Dynamic = 0,
Static = 1,
Kinematic = 2,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum KeyName {
Return,
Escape,
BackSpace,
Tab,
Space,
Exclamation,
DoubleQuote,
Hash,
Percent,
Dollar,
Ampersand,
SingleQuote,
LeftParen,
RightParen,
Asterisk,
Plus,
Comma,
Minus,
Dot,
Slash,
Num1,
Num2,
Num3,
Num4,
Num5,
Num6,
Num7,
Num8,
Num9,
Num0,
Colon,
Semicolon,
LessThan,
Equal,
GreaterThan,
Question,
At,
LeftBracket,
Backslash,
RightBracket,
Caret,
Underscore,
Backtick,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Delete,
CapsLock,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
PrintScreen,
ScrollLock,
Pause,
Insert,
Home,
PageUp,
End,
PageDown,
Right,
Left,
Down,
Up,
Application,
LCtrl,
LShift,
LAlt,
LGui,
RCtrl,
RShift,
RAlt,
RGui,
}
impl AsRef<str> for KeyName {
fn as_ref(&self) -> &str {
match self {
KeyName::Return => "Return",
KeyName::Escape => "Escape",
KeyName::BackSpace => "BackSpace",
KeyName::Tab => "Tab",
KeyName::Space => "Space",
KeyName::Exclamation => "!",
KeyName::DoubleQuote => "\"",
KeyName::Hash => "#",
KeyName::Percent => "%",
KeyName::Dollar => "$",
KeyName::Ampersand => "&",
KeyName::SingleQuote => "'",
KeyName::LeftParen => "(",
KeyName::RightParen => ")",
KeyName::Asterisk => "*",
KeyName::Plus => "+",
KeyName::Comma => ",",
KeyName::Minus => "-",
KeyName::Dot => ".",
KeyName::Slash => "/",
KeyName::Num1 => "1",
KeyName::Num2 => "2",
KeyName::Num3 => "3",
KeyName::Num4 => "4",
KeyName::Num5 => "5",
KeyName::Num6 => "6",
KeyName::Num7 => "7",
KeyName::Num8 => "8",
KeyName::Num9 => "9",
KeyName::Num0 => "0",
KeyName::Colon => ":",
KeyName::Semicolon => ";",
KeyName::LessThan => "<",
KeyName::Equal => "=",
KeyName::GreaterThan => ">",
KeyName::Question => "?",
KeyName::At => "@",
KeyName::LeftBracket => "[",
KeyName::Backslash => "\\",
KeyName::RightBracket => "]",
KeyName::Caret => "^",
KeyName::Underscore => "_",
KeyName::Backtick => "`",
KeyName::A => "A",
KeyName::B => "B",
KeyName::C => "C",
KeyName::D => "D",
KeyName::E => "E",
KeyName::F => "F",
KeyName::G => "G",
KeyName::H => "H",
KeyName::I => "I",
KeyName::J => "J",
KeyName::K => "K",
KeyName::L => "L",
KeyName::M => "M",
KeyName::N => "N",
KeyName::O => "O",
KeyName::P => "P",
KeyName::Q => "Q",
KeyName::R => "R",
KeyName::S => "S",
KeyName::T => "T",
KeyName::U => "U",
KeyName::V => "V",
KeyName::W => "W",
KeyName::X => "X",
KeyName::Y => "Y",
KeyName::Z => "Z",
KeyName::Delete => "Delete",
KeyName::CapsLock => "CapsLock",
KeyName::F1 => "F1",
KeyName::F2 => "F2",
KeyName::F3 => "F3",
KeyName::F4 => "F4",
KeyName::F5 => "F5",
KeyName::F6 => "F6",
KeyName::F7 => "F7",
KeyName::F8 => "F8",
KeyName::F9 => "F9",
KeyName::F10 => "F10",
KeyName::F11 => "F11",
KeyName::F12 => "F12",
KeyName::PrintScreen => "PrintScreen",
KeyName::ScrollLock => "ScrollLock",
KeyName::Pause => "Pause",
KeyName::Insert => "Insert",
KeyName::Home => "Home",
KeyName::PageUp => "PageUp",
KeyName::End => "End",
KeyName::PageDown => "PageDown",
KeyName::Right => "Right",
KeyName::Left => "Left",
KeyName::Down => "Down",
KeyName::Up => "Up",
KeyName::Application => "Application",
KeyName::LCtrl => "LCtrl",
KeyName::LShift => "LShift",
KeyName::LAlt => "LAlt",
KeyName::LGui => "LGui",
KeyName::RCtrl => "RCtrl",
KeyName::RShift => "RShift",
KeyName::RAlt => "RAlt",
KeyName::RGui => "RGui",
}
}
}
impl Keyboard {
pub fn is_key_down(key: KeyName) -> bool {
Keyboard::_is_key_down(key.as_ref())
}
pub fn is_key_up(key: KeyName) -> bool {
Keyboard::_is_key_up(key.as_ref())
}
pub fn is_key_pressed(key: KeyName) -> bool {
Keyboard::_is_key_pressed(key.as_ref())
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AxisName {
LeftX,
LeftY,
RightX,
RightY,
LeftTrigger,
RightTrigger,
}
impl AsRef<str> for AxisName {
fn as_ref(&self) -> &str {
match self {
AxisName::LeftX => "leftx",
AxisName::LeftY => "lefty",
AxisName::RightX => "rightx",
AxisName::RightY => "righty",
AxisName::LeftTrigger => "lefttrigger",
AxisName::RightTrigger => "righttrigger",
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ButtonName {
A,
B,
Back,
DPDown,
DPLeft,
DPRight,
DPUp,
LeftShoulder,
LeftStick,
RightShoulder,
RightStick,
Start,
X,
Y,
}
impl AsRef<str> for ButtonName {
fn as_ref(&self) -> &str {
match self {
ButtonName::A => "a",
ButtonName::B => "b",
ButtonName::Back => "back",
ButtonName::DPDown => "dpdown",
ButtonName::DPLeft => "dpleft",
ButtonName::DPRight => "dpright",
ButtonName::DPUp => "dpup",
ButtonName::LeftShoulder => "leftshoulder",
ButtonName::LeftStick => "leftstick",
ButtonName::RightShoulder => "rightshoulder",
ButtonName::RightStick => "rightstick",
ButtonName::Start => "start",
ButtonName::X => "x",
ButtonName::Y => "y",
}
}
}
impl Controller {
pub fn is_button_down(controller_id: i32, button: ButtonName) -> bool {
Controller::_is_button_down(controller_id, button.as_ref())
}
pub fn is_button_up(controller_id: i32, button: ButtonName) -> bool {
Controller::_is_button_up(controller_id, button.as_ref())
}
pub fn is_button_pressed(controller_id: i32, button: ButtonName) -> bool {
Controller::_is_button_pressed(controller_id, button.as_ref())
}
pub fn get_axis(controller_id: i32, axis: AxisName) -> f32 {
Controller::_get_axis(controller_id, axis.as_ref())
}
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AttenuationModel {
NoAttenuation = 0,
InverseDistance = 1,
LinearDistance = 2,
ExponentialDistance = 3,
}
impl platformer::ActionUpdate {
pub fn from_update(mut update: Box<dyn FnMut(f64) -> bool>) -> platformer::ActionUpdate {
platformer::ActionUpdate::new(Box::new(move |_, _, dt| update(dt as f64)))
}
}
extern "C" {
fn blackboard_set(b: i64, k: i64, v: i64);
fn blackboard_get(b: i64, k: i64) -> i64;
}
impl platformer::behavior::Blackboard {
pub fn set<'a, T>(&mut self, key: &str, value: T)
where
T: IntoValue<'a>,
{
unsafe {
blackboard_set(self.raw(), from_string(key), value.val().raw());
}
}
pub fn get(&self, key: &str) -> Option<Value> {
Value::from(unsafe { blackboard_get(self.raw(), from_string(key)) })
}
}
pub use enumflags2::BitFlags;
use enumflags2::{bitflags, make_bitflags};
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiSliderFlag {
Logarithmic = 1 << 5,
NoRoundToFormat = 1 << 6,
NoInput = 1 << 7,
WrapAround = 1 << 8,
ClampOnInput = 1 << 9,
ClampZeroRange = 1 << 10,
}
impl ImGuiSliderFlag {
pub const ALWAYS_CLAMP: BitFlags<Self> = make_bitflags!(Self::{ClampOnInput | ClampZeroRange});
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiWindowFlag {
NoTitleBar = 1 << 0,
NoResize = 1 << 1,
NoMove = 1 << 2,
NoScrollbar = 1 << 3,
NoScrollWithMouse = 1 << 4,
NoCollapse = 1 << 5,
AlwaysAutoResize = 1 << 6,
NoBackground = 1 << 7,
NoSavedSettings = 1 << 8,
NoMouseInputs = 1 << 9,
MenuBar = 1 << 10,
HorizontalScrollbar = 1 << 11,
NoFocusOnAppearing = 1 << 12,
NoBringToFrontOnFocus = 1 << 13,
AlwaysVerticalScrollbar = 1 << 14,
AlwaysHorizontalScrollbar = 1 << 15,
NoNavInputs = 1 << 16,
NoNavFocus = 1 << 17,
UnsavedDocument = 1 << 18,
}
impl ImGuiWindowFlag {
pub const NO_NAV: BitFlags<Self> = make_bitflags!(Self::{NoNavInputs | NoNavFocus});
pub const NO_DECORATION: BitFlags<Self> =
make_bitflags!(Self::{NoTitleBar | NoResize | NoScrollbar | NoCollapse});
pub const NO_INPUTS: BitFlags<Self> =
make_bitflags!(Self::{NoMouseInputs | NoNavInputs | NoNavFocus});
}
#[bitflags]
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiChildFlag {
Borders = 1 << 0,
AlwaysUseWindowPadding = 1 << 1,
ResizeX = 1 << 2,
ResizeY = 1 << 3,
AutoResizeX = 1 << 4,
AutoResizeY = 1 << 5,
AlwaysAutoResize = 1 << 6,
FrameStyle = 1 << 7,
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiInputTextFlag {
CharsDecimal = 1 << 0,
CharsHexadecimal = 1 << 1,
CharsScientific = 1 << 2,
CharsUppercase = 1 << 3,
CharsNoBlank = 1 << 4,
AllowTabInput = 1 << 5,
EnterReturnsTrue = 1 << 6,
EscapeClearsAll = 1 << 7,
CtrlEnterForNewLine = 1 << 8,
ReadOnly = 1 << 9,
Password = 1 << 10,
AlwaysOverwrite = 1 << 11,
AutoSelectAll = 1 << 12,
ParseEmptyRefVal = 1 << 13,
DisplayEmptyRefVal = 1 << 14,
NoHorizontalScroll = 1 << 15,
NoUndoRedo = 1 << 16,
ElideLeft = 1 << 17,
CallbackCompletion = 1 << 18,
CallbackHistory = 1 << 19,
CallbackAlways = 1 << 20,
CallbackCharFilter = 1 << 21,
CallbackResize = 1 << 22,
CallbackEdit = 1 << 23,
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiTreeNodeFlag {
Selected = 1 << 0,
Framed = 1 << 1,
AllowOverlap = 1 << 2,
NoTreePushOnOpen = 1 << 3,
NoAutoOpenOnLog = 1 << 4,
DefaultOpen = 1 << 5,
OpenOnDoubleClick = 1 << 6,
OpenOnArrow = 1 << 7,
Leaf = 1 << 8,
Bullet = 1 << 9,
FramePadding = 1 << 10,
SpanAvailWidth = 1 << 11,
SpanFullWidth = 1 << 12,
SpanLabelWidth = 1 << 13,
SpanAllColumns = 1 << 14,
LabelSpanAllColumns = 1 << 15,
NavLeftJumpsToParent = 1 << 17,
}
impl ImGuiTreeNodeFlag {
pub const COLLAPSING_HEADER: BitFlags<Self> =
make_bitflags!(Self::{Framed | NoTreePushOnOpen | NoAutoOpenOnLog});
}
#[bitflags]
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiSelectableFlag {
DontClosePopups = 1 << 0,
SpanAllColumns = 1 << 1,
AllowDoubleClick = 1 << 2,
Disabled = 1 << 3,
AllowOverlap = 1 << 4,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiCol {
Text,
TextDisabled,
WindowBg,
ChildBg,
PopupBg,
Border,
BorderShadow,
FrameBg,
FrameBgHovered,
FrameBgActive,
TitleBg,
TitleBgActive,
TitleBgCollapsed,
MenuBarBg,
ScrollbarBg,
ScrollbarGrab,
ScrollbarGrabHovered,
ScrollbarGrabActive,
CheckMark,
SliderGrab,
SliderGrabActive,
Button,
ButtonHovered,
ButtonActive,
Header,
HeaderHovered,
HeaderActive,
Separator,
SeparatorHovered,
SeparatorActive,
ResizeGrip,
ResizeGripHovered,
ResizeGripActive,
TabHovered,
Tab,
TabSelected,
TabSelectedOverline,
TabDimmed,
TabDimmedSelected,
TabDimmedSelectedOverline,
PlotLines,
PlotLinesHovered,
PlotHistogram,
PlotHistogramHovered,
TableHeaderBg,
TableBorderStrong,
TableBorderLight,
TableRowBg,
TableRowBgAlt,
TextLink,
TextSelectedBg,
DragDropTarget,
NavCursor,
NavWindowingHighlight,
NavWindowingDimBg,
ModalWindowDimBg,
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiColorEditFlag {
NoAlpha = 1 << 1,
NoPicker = 1 << 2,
NoOptions = 1 << 3,
NoSmallPreview = 1 << 4,
NoInputs = 1 << 5,
NoTooltip = 1 << 6,
NoLabel = 1 << 7,
NoSidePreview = 1 << 8,
NoDragDrop = 1 << 9,
NoBorder = 1 << 10,
AlphaOpaque = 1 << 11,
AlphaNoBg = 1 << 12,
AlphaPreviewHalf = 1 << 13,
AlphaBar = 1 << 16,
HDR = 1 << 19,
DisplayRGB = 1 << 20,
DisplayHSV = 1 << 21,
DisplayHex = 1 << 22,
Uint8 = 1 << 23,
Float = 1 << 24,
PickerHueBar = 1 << 25,
PickerHueWheel = 1 << 26,
InputRGB = 1 << 27,
InputHSV = 1 << 28,
}
impl ImGuiColorEditFlag {
pub const DEFAULT_OPTIONS: BitFlags<Self> =
make_bitflags!(Self::{Uint8 | DisplayRGB | InputRGB | PickerHueBar});
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiCond {
Always = 1 << 0,
Once = 1 << 1,
FirstUseEver = 1 << 2,
Appearing = 1 << 3,
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiTableFlag {
Resizable = 1 << 0,
Reorderable = 1 << 1,
Hideable = 1 << 2,
Sortable = 1 << 3,
NoSavedSettings = 1 << 4,
ContextMenuInBody = 1 << 5,
RowBg = 1 << 6,
BordersInnerH = 1 << 7,
BordersOuterH = 1 << 8,
BordersInnerV = 1 << 9,
BordersOuterV = 1 << 10,
NoBordersInBody = 1 << 11,
NoBordersInBodyUntilResize = 1 << 12,
SizingFixedFit = 1 << 13,
SizingFixedSame = 1 << 14,
SizingStretchSame = 1 << 15,
NoHostExtendX = 1 << 16,
NoHostExtendY = 1 << 17,
NoKeepColumnsVisible = 1 << 18,
PreciseWidths = 1 << 19,
NoClip = 1 << 20,
PadOuterX = 1 << 21,
NoPadOuterX = 1 << 22,
NoPadInnerX = 1 << 23,
ScrollX = 1 << 24,
ScrollY = 1 << 25,
SortMulti = 1 << 26,
SortTristate = 1 << 27,
HighlightHoveredColumn = 1 << 28,
}
impl ImGuiTableFlag {
pub const BORDERS_H: BitFlags<Self> = make_bitflags!(Self::{BordersInnerH | BordersOuterH});
pub const BORDERS_V: BitFlags<Self> = make_bitflags!(Self::{BordersInnerV | BordersOuterV});
pub const BORDERS_INNER: BitFlags<Self> = make_bitflags!(Self::{BordersInnerV | BordersInnerH});
pub const BORDERS_OUTER: BitFlags<Self> = make_bitflags!(Self::{BordersOuterV | BordersOuterH});
pub const BORDERS: BitFlags<Self> =
make_bitflags!(Self::{BordersInnerV | BordersInnerH | BordersOuterV | BordersOuterH});
pub const SIZING_STRETCH_PROP: BitFlags<Self> =
make_bitflags!(Self::{SizingFixedFit | SizingFixedSame});
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiTableColumnFlag {
Disabled = 1 << 0,
DefaultHide = 1 << 1,
DefaultSort = 1 << 2,
WidthStretch = 1 << 3,
WidthFixed = 1 << 4,
NoResize = 1 << 5,
NoReorder = 1 << 6,
NoHide = 1 << 7,
NoClip = 1 << 8,
NoSort = 1 << 9,
NoSortAscending = 1 << 10,
NoSortDescending = 1 << 11,
NoHeaderLabel = 1 << 12,
NoHeaderWidth = 1 << 13,
PreferSortAscending = 1 << 14,
PreferSortDescending = 1 << 15,
IndentEnable = 1 << 16,
IndentDisable = 1 << 17,
AngledHeader = 1 << 18,
IsEnabled = 1 << 24,
IsVisible = 1 << 25,
IsSorted = 1 << 26,
IsHovered = 1 << 27,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiPopupButton {
MouseButtonLeft = 0,
MouseButtonRight = 1,
MouseButtonMiddle = 2,
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiPopupFlag {
NoReopen = 1 << 5,
NoOpenOverExistingPopup = 1 << 7,
NoOpenOverItems = 1 << 8,
AnyPopupId = 1 << 10,
AnyPopupLevel = 1 << 11,
}
impl ImGuiPopupFlag {
pub const ANY_POPUP: BitFlags<Self> = make_bitflags!(Self::{AnyPopupId | AnyPopupLevel});
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiStyleVar {
Alpha = 0,
DisabledAlpha = 1,
WindowRounding = 3,
WindowBorderSize = 4,
ChildRounding = 7,
ChildBorderSize = 8,
PopupRounding = 9,
PopupBorderSize = 10,
FrameRounding = 12,
FrameBorderSize = 13,
IndentSpacing = 16,
ScrollbarSize = 18,
ScrollbarRounding = 19,
GrabMinSize = 20,
GrabRounding = 21,
TabRounding = 22,
TabBarBorderSize = 23,
SeparatorTextBorderSize = 26,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiStyleVec2 {
WindowPadding = 2,
WindowMinSize = 5,
WindowTitleAlign = 6,
FramePadding = 11,
ItemSpacing = 14,
ItemInnerSpacing = 15,
CellPadding = 17,
ButtonTextAlign = 24,
SelectableTextAlign = 25,
SeparatorTextAlign = 27,
SeparatorTextPadding = 28,
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiItemFlag {
NoTabStop = 1 << 0,
NoNav = 1 << 1,
NoNavDefaultFocus = 1 << 2,
ButtonRepeat = 1 << 3,
AutoClosePopups = 1 << 4,
AllowDuplicateId = 1 << 5,
}
#[bitflags]
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiTableRowFlag {
Headers = 1 << 0,
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiTabBarFlag {
Reorderable = 1 << 0,
AutoSelectNewTabs = 1 << 1,
TabListPopupButton = 1 << 2,
NoCloseWithMiddleMouseButton = 1 << 3,
NoTabListScrollingButtons = 1 << 4,
NoTooltip = 1 << 5,
DrawSelectedOverline = 1 << 6,
FittingPolicyShrink = 1 << 7,
FittingPolicyScroll = 1 << 8,
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ImGuiTabItemFlag {
UnsavedDocument = 1 << 0,
SetSelected = 1 << 1,
NoCloseWithMiddleMouseButton = 1 << 2,
NoPushId = 1 << 3,
NoTooltip = 1 << 4,
NoReorder = 1 << 5,
Leading = 1 << 6,
Trailing = 1 << 7,
NoAssumedClosure = 1 << 8,
}
thread_local! {
static IMGUI_STACK: RefCell<CallStack> = RefCell::new(CallStack::new());
}
impl ImGui {
pub fn begin<C>(name: &str, inside: C)
where
C: FnOnce(),
{
ImGui::begin_opts(name, BitFlags::default(), inside);
}
pub fn begin_opts<C>(name: &str, windows_flags: BitFlags<ImGuiWindowFlag>, inside: C)
where
C: FnOnce(),
{
if ImGui::_begin_opts(name, windows_flags.bits() as i32) {
inside();
}
ImGui::_end();
}
pub fn begin_ret<C>(name: &str, opened: bool, inside: C) -> bool
where
C: FnOnce(),
{
ImGui::begin_ret_opts(name, opened, BitFlags::default(), inside)
}
pub fn begin_ret_opts<C>(
name: &str,
opened: bool,
windows_flags: BitFlags<ImGuiWindowFlag>,
inside: C,
) -> bool
where
C: FnOnce(),
{
let mut changed = false;
let mut result = false;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_bool(opened);
changed = ImGui::_begin_ret_opts(name, stack, windows_flags.bits() as i32);
result = stack.pop_bool().unwrap();
});
if result {
inside();
}
ImGui::_end();
changed
}
pub fn begin_child<C>(str_id: &str, inside: C)
where
C: FnOnce(),
{
ImGui::begin_child_opts(
str_id,
&Vec2::zero(),
BitFlags::default(),
BitFlags::default(),
inside,
);
}
pub fn begin_child_opts<C>(
str_id: &str,
size: &crate::dora::Vec2,
child_flags: BitFlags<ImGuiChildFlag>,
window_flags: BitFlags<ImGuiWindowFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_begin_child_opts(
str_id,
size,
child_flags.bits() as i32,
window_flags.bits() as i32,
) {
inside();
}
ImGui::_end_child();
}
pub fn begin_child_with_id<C>(id: i32, inside: C)
where
C: FnOnce(),
{
ImGui::begin_child_with_id_opts(
id,
&Vec2::zero(),
BitFlags::default(),
BitFlags::default(),
inside,
);
}
pub fn begin_child_with_id_opts<C>(
id: i32,
size: &crate::dora::Vec2,
child_flags: BitFlags<ImGuiChildFlag>,
window_flags: BitFlags<ImGuiWindowFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_begin_child_with_id_opts(
id,
size,
child_flags.bits() as i32,
window_flags.bits() as i32,
) {
inside();
}
ImGui::_end_child();
}
pub fn collapsing_header_ret(label: &str, opened: bool) -> (bool, bool) {
ImGui::collapsing_header_ret_opts(label, opened, BitFlags::default())
}
pub fn collapsing_header_ret_opts(
label: &str,
opened: bool,
tree_node_flags: BitFlags<ImGuiTreeNodeFlag>,
) -> (bool, bool) {
let mut changed = false;
let mut result = false;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_bool(opened);
changed =
ImGui::_collapsing_header_ret_opts(label, stack, tree_node_flags.bits() as i32);
result = stack.pop_bool().unwrap();
});
(changed, result)
}
pub fn selectable_ret(label: &str, selected: bool) -> (bool, bool) {
ImGui::selectable_ret_opts(label, selected, &Vec2::zero(), BitFlags::default())
}
pub fn selectable_ret_opts(
label: &str,
selected: bool,
size: &crate::dora::Vec2,
selectable_flags: BitFlags<ImGuiSelectableFlag>,
) -> (bool, bool) {
let mut changed = false;
let mut result = false;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_bool(selected);
changed =
ImGui::_selectable_ret_opts(label, stack, size, selectable_flags.bits() as i32);
result = stack.pop_bool().unwrap();
});
(changed, result)
}
pub fn combo_ret(label: &str, current_item: i32, items: &Vec<&str>) -> (bool, i32) {
ImGui::combo_ret_opts(label, current_item, items, -1)
}
pub fn combo_ret_opts(
label: &str,
current_item: i32,
items: &Vec<&str>,
height_in_items: i32,
) -> (bool, i32) {
let mut changed = false;
let mut result = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(current_item);
changed = ImGui::_combo_ret_opts(label, stack, items, height_in_items);
result = stack.pop_i32().unwrap();
});
(changed, result)
}
pub fn drag_float_ret(
label: &str,
v: f32,
v_speed: f32,
v_min: f32,
v_max: f32,
) -> (bool, f32) {
ImGui::drag_float_ret_opts(label, v, v_speed, v_min, v_max, "%.2f", BitFlags::default())
}
pub fn drag_float_ret_opts(
label: &str,
v: f32,
v_speed: f32,
v_min: f32,
v_max: f32,
display_format: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, f32) {
let mut changed = false;
let mut result = 0_f32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_f32(v);
changed = ImGui::_drag_float_ret_opts(
label,
stack,
v_speed,
v_min,
v_max,
display_format,
slider_flags.bits() as i32,
);
result = stack.pop_f32().unwrap();
});
(changed, result)
}
pub fn drag_float2_ret(
label: &str,
v1: f32,
v2: f32,
v_speed: f32,
v_min: f32,
v_max: f32,
) -> (bool, f32, f32) {
ImGui::drag_float2_ret_opts(
label,
v1,
v2,
v_speed,
v_min,
v_max,
"%.2f",
BitFlags::default(),
)
}
pub fn drag_float2_ret_opts(
label: &str,
v1: f32,
v2: f32,
v_speed: f32,
v_min: f32,
v_max: f32,
display_format: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, f32, f32) {
let mut changed = false;
let mut result1 = 0_f32;
let mut result2 = 0_f32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_f32(v1);
stack.push_f32(v2);
changed = ImGui::_drag_float2_ret_opts(
label,
stack,
v_speed,
v_min,
v_max,
display_format,
slider_flags.bits() as i32,
);
result1 = stack.pop_f32().unwrap();
result2 = stack.pop_f32().unwrap();
});
(changed, result1, result2)
}
pub fn drag_int2_ret(
label: &str,
v1: i32,
v2: i32,
v_speed: f32,
v_min: i32,
v_max: i32,
) -> (bool, i32, i32) {
ImGui::drag_int2_ret_opts(label, v1, v2, v_speed, v_min, v_max, "%d", BitFlags::default())
}
pub fn drag_int2_ret_opts(
label: &str,
v1: i32,
v2: i32,
v_speed: f32,
v_min: i32,
v_max: i32,
display_format: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, i32, i32) {
let mut changed = false;
let mut result1 = 0_i32;
let mut result2 = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(v1);
stack.push_i32(v2);
changed = ImGui::_drag_int2_ret_opts(
label,
stack,
v_speed,
v_min,
v_max,
display_format,
slider_flags.bits() as i32,
);
result1 = stack.pop_i32().unwrap();
result2 = stack.pop_i32().unwrap();
});
(changed, result1, result2)
}
pub fn input_float_ret(label: &str, v: f32) -> (bool, f32) {
ImGui::input_float_ret_opts(label, v, 0.0, 0.0, "%.2f", BitFlags::default())
}
pub fn input_float_ret_opts(
label: &str,
v: f32,
step: f32,
step_fast: f32,
display_format: &str,
input_text_flags: BitFlags<ImGuiInputTextFlag>,
) -> (bool, f32) {
let mut changed = false;
let mut result = 0_f32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_f32(v);
changed = ImGui::_input_float_ret_opts(
label,
stack,
step,
step_fast,
display_format,
input_text_flags.bits() as i32,
);
result = stack.pop_f32().unwrap();
});
(changed, result)
}
pub fn input_float2_ret(label: &str, v1: f32, v2: f32) -> (bool, f32, f32) {
ImGui::input_float2_ret_opts(label, v1, v2, "%.2f", BitFlags::default())
}
pub fn input_float2_ret_opts(
label: &str,
v1: f32,
v2: f32,
display_format: &str,
input_text_flags: BitFlags<ImGuiInputTextFlag>,
) -> (bool, f32, f32) {
let mut changed = false;
let mut result1 = 0_f32;
let mut result2 = 0_f32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_f32(v1);
stack.push_f32(v2);
changed = ImGui::_input_float2_ret_opts(
label,
stack,
display_format,
input_text_flags.bits() as i32,
);
result1 = stack.pop_f32().unwrap();
result2 = stack.pop_f32().unwrap();
});
(changed, result1, result2)
}
pub fn input_int_ret(label: &str, v: i32) -> (bool, i32) {
ImGui::input_int_ret_opts(label, v, 1, 100, BitFlags::default())
}
pub fn input_int_ret_opts(
label: &str,
v: i32,
step: i32,
step_fast: i32,
input_text_flags: BitFlags<ImGuiInputTextFlag>,
) -> (bool, i32) {
let mut changed = false;
let mut result = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(v);
changed = ImGui::_input_int_ret_opts(
label,
stack,
step,
step_fast,
input_text_flags.bits() as i32,
);
result = stack.pop_i32().unwrap();
});
(changed, result)
}
pub fn input_int2_ret(label: &str, v1: i32, v2: i32) -> (bool, i32, i32) {
ImGui::input_int2_ret_opts(label, v1, v2, BitFlags::default())
}
pub fn input_int2_ret_opts(
label: &str,
v1: i32,
v2: i32,
input_text_flags: BitFlags<ImGuiInputTextFlag>,
) -> (bool, i32, i32) {
let mut changed = false;
let mut result1 = 0_i32;
let mut result2 = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(v1);
stack.push_i32(v2);
changed = ImGui::_input_int2_ret_opts(label, stack, input_text_flags.bits() as i32);
result1 = stack.pop_i32().unwrap();
result2 = stack.pop_i32().unwrap();
});
(changed, result1, result2)
}
pub fn slider_float_ret(label: &str, v: f32, v_min: f32, v_max: f32) -> (bool, f32) {
ImGui::slider_float_ret_opts(label, v, v_min, v_max, "%.2f", BitFlags::default())
}
pub fn slider_float_ret_opts(
label: &str,
v: f32,
v_min: f32,
v_max: f32,
display_format: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, f32) {
let mut changed = false;
let mut result = 0_f32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_f32(v);
changed = ImGui::_slider_float_ret_opts(
label,
stack,
v_min,
v_max,
display_format,
slider_flags.bits() as i32,
);
result = stack.pop_f32().unwrap();
});
(changed, result)
}
pub fn slider_float2_ret(
label: &str,
v1: f32,
v2: f32,
v_min: f32,
v_max: f32,
) -> (bool, f32, f32) {
ImGui::slider_float2_ret_opts(label, v1, v2, v_min, v_max, "%.2f", BitFlags::default())
}
pub fn slider_float2_ret_opts(
label: &str,
v1: f32,
v2: f32,
v_min: f32,
v_max: f32,
display_format: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, f32, f32) {
let mut changed = false;
let mut result1 = 0_f32;
let mut result2 = 0_f32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_f32(v1);
stack.push_f32(v2);
changed = ImGui::_slider_float2_ret_opts(
label,
stack,
v_min,
v_max,
display_format,
slider_flags.bits() as i32,
);
result1 = stack.pop_f32().unwrap();
result2 = stack.pop_f32().unwrap();
});
(changed, result1, result2)
}
pub fn drag_float_range2_ret(
label: &str,
v_current_min: f32,
v_current_max: f32,
v_speed: f32,
v_min: f32,
v_max: f32,
) -> (bool, f32, f32) {
ImGui::drag_float_range2_ret_opts(
label,
v_current_min,
v_current_max,
v_speed,
v_min,
v_max,
"%.2f",
"%.2f",
BitFlags::default(),
)
}
pub fn drag_float_range2_ret_opts(
label: &str,
v_current_min: f32,
v_current_max: f32,
v_speed: f32,
v_min: f32,
v_max: f32,
format: &str,
format_max: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, f32, f32) {
let mut changed = false;
let mut result1 = 0_f32;
let mut result2 = 0_f32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_f32(v_current_min);
stack.push_f32(v_current_max);
changed = ImGui::_drag_float_range2_ret_opts(
label,
stack,
v_speed,
v_min,
v_max,
format,
format_max,
slider_flags.bits() as i32,
);
result1 = stack.pop_f32().unwrap();
result2 = stack.pop_f32().unwrap();
});
(changed, result1, result2)
}
pub fn drag_int_ret(
label: &str,
value: i32,
v_speed: f32,
v_min: i32,
v_max: i32,
) -> (bool, i32) {
ImGui::drag_int_ret_opts(label, value, v_speed, v_min, v_max, "%d", BitFlags::default())
}
pub fn drag_int_ret_opts(
label: &str,
value: i32,
v_speed: f32,
v_min: i32,
v_max: i32,
display_format: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, i32) {
let mut changed = false;
let mut result = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(value);
changed = ImGui::_drag_int_ret_opts(
label,
stack,
v_speed,
v_min,
v_max,
display_format,
slider_flags.bits() as i32,
);
result = stack.pop_i32().unwrap();
});
(changed, result)
}
pub fn drag_int_range2_ret(
label: &str,
v_current_min: i32,
v_current_max: i32,
v_speed: f32,
v_min: i32,
v_max: i32,
) -> (bool, i32, i32) {
ImGui::drag_int_range2_ret_opts(
label,
v_current_min,
v_current_max,
v_speed,
v_min,
v_max,
"%d",
"%d",
BitFlags::default(),
)
}
pub fn drag_int_range2_ret_opts(
label: &str,
v_current_min: i32,
v_current_max: i32,
v_speed: f32,
v_min: i32,
v_max: i32,
format: &str,
format_max: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, i32, i32) {
let mut changed = false;
let mut result1 = 0_i32;
let mut result2 = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(v_current_min);
stack.push_i32(v_current_max);
changed = ImGui::_drag_int_range2_ret_opts(
label,
stack,
v_speed,
v_min,
v_max,
format,
format_max,
slider_flags.bits() as i32,
);
result1 = stack.pop_i32().unwrap();
result2 = stack.pop_i32().unwrap();
});
(changed, result1, result2)
}
pub fn slider_int_ret(label: &str, value: i32, v_min: i32, v_max: i32) -> (bool, i32) {
ImGui::slider_int_ret_opts(label, value, v_min, v_max, "%d", BitFlags::default())
}
pub fn slider_int_ret_opts(
label: &str,
value: i32,
v_min: i32,
v_max: i32,
format: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, i32) {
let mut changed = false;
let mut result = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(value);
changed = ImGui::_slider_int_ret_opts(
label,
stack,
v_min,
v_max,
format,
slider_flags.bits() as i32,
);
result = stack.pop_i32().unwrap();
});
(changed, result)
}
pub fn slider_int2_ret(
label: &str,
v1: i32,
v2: i32,
v_min: i32,
v_max: i32,
) -> (bool, i32, i32) {
ImGui::slider_int2_ret_opts(label, v1, v2, v_min, v_max, "%d", BitFlags::default())
}
pub fn slider_int2_ret_opts(
label: &str,
v1: i32,
v2: i32,
v_min: i32,
v_max: i32,
display_format: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, i32, i32) {
let mut changed = false;
let mut result1 = 0_i32;
let mut result2 = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(v1);
stack.push_i32(v2);
changed = ImGui::_slider_int2_ret_opts(
label,
stack,
v_min,
v_max,
display_format,
slider_flags.bits() as i32,
);
result1 = stack.pop_i32().unwrap();
result2 = stack.pop_i32().unwrap();
});
(changed, result1, result2)
}
pub fn v_slider_float_ret(
label: &str,
size: &crate::dora::Vec2,
v: f32,
v_min: f32,
v_max: f32,
) -> (bool, f32) {
ImGui::v_slider_float_ret_opts(label, size, v, v_min, v_max, "%.2f", BitFlags::default())
}
pub fn v_slider_float_ret_opts(
label: &str,
size: &crate::dora::Vec2,
v: f32,
v_min: f32,
v_max: f32,
format: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, f32) {
let mut changed = false;
let mut result = 0_f32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_f32(v);
changed = ImGui::_v_slider_float_ret_opts(
label,
size,
stack,
v_min,
v_max,
format,
slider_flags.bits() as i32,
);
result = stack.pop_f32().unwrap();
});
(changed, result)
}
pub fn v_slider_int_ret(
label: &str,
size: &crate::dora::Vec2,
v: i32,
v_min: i32,
v_max: i32,
) -> (bool, i32) {
ImGui::v_slider_int_ret_opts(label, size, v, v_min, v_max, "%d", BitFlags::default())
}
pub fn v_slider_int_ret_opts(
label: &str,
size: &crate::dora::Vec2,
v: i32,
v_min: i32,
v_max: i32,
format: &str,
slider_flags: BitFlags<ImGuiSliderFlag>,
) -> (bool, i32) {
let mut changed = false;
let mut result = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(v);
changed = ImGui::_v_slider_int_ret_opts(
label,
size,
stack,
v_min,
v_max,
format,
slider_flags.bits() as i32,
);
result = stack.pop_i32().unwrap();
});
(changed, result)
}
pub fn color_edit3_ret(label: &str, color3: &Color3) -> (bool, Color3) {
ImGui::color_edit3_ret_opts(label, color3, BitFlags::default())
}
pub fn color_edit3_ret_opts(
label: &str,
color3: &Color3,
color_edit_flags: BitFlags<ImGuiColorEditFlag>,
) -> (bool, Color3) {
let mut changed = false;
let mut result = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(color3.to_rgb() as i32);
changed = ImGui::_color_edit3_ret_opts(label, stack, color_edit_flags.bits() as i32);
result = stack.pop_i32().unwrap();
});
(changed, Color3::new(result as u32))
}
pub fn color_edit4_ret(label: &str, color: &Color) -> (bool, Color) {
ImGui::color_edit4_ret_opts(label, color, BitFlags::default())
}
pub fn color_edit4_ret_opts(
label: &str,
color: &Color,
color_edit_flags: BitFlags<ImGuiColorEditFlag>,
) -> (bool, Color) {
let mut changed = false;
let mut result = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(color.to_argb() as i32);
changed = ImGui::_color_edit4_ret_opts(label, stack, color_edit_flags.bits() as i32);
result = stack.pop_i32().unwrap();
});
(changed, Color::new(result as u32))
}
pub fn checkbox_ret(label: &str, checked: bool) -> (bool, bool) {
let mut changed = false;
let mut result = false;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_bool(checked);
changed = ImGui::_checkbox_ret(label, stack);
result = stack.pop_bool().unwrap();
});
(changed, result)
}
pub fn radio_button_ret(label: &str, value: i32, v_button: i32) -> (bool, i32) {
let mut changed = false;
let mut result = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(value);
changed = ImGui::_radio_button_ret(label, stack, v_button);
result = stack.pop_i32().unwrap();
});
(changed, result)
}
pub fn list_box_ret(label: &str, current_item: i32, items: &Vec<&str>) -> (bool, i32) {
ImGui::list_box_ret_opts(label, current_item, items, -1)
}
pub fn list_box_ret_opts(
label: &str,
current_item: i32,
items: &Vec<&str>,
height_in_items: i32,
) -> (bool, i32) {
let mut changed = false;
let mut result = 0_i32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_i32(current_item);
changed = ImGui::_list_box_ret_opts(label, stack, items, height_in_items);
result = stack.pop_i32().unwrap();
});
(changed, result)
}
pub fn set_next_window_pos_center() {
ImGui::set_next_window_pos_center_opts(ImGuiCond::Always);
}
pub fn set_next_window_pos_center_opts(set_cond: ImGuiCond) {
ImGui::_set_next_window_pos_center_opts(set_cond as i32);
}
pub fn set_next_window_size(size: &crate::dora::Vec2) {
ImGui::set_next_window_size_opts(size, ImGuiCond::Always);
}
pub fn set_next_window_size_opts(size: &crate::dora::Vec2, set_cond: ImGuiCond) {
ImGui::_set_next_window_size_opts(size, set_cond as i32);
}
pub fn set_next_window_collapsed(collapsed: bool) {
ImGui::set_next_window_collapsed_opts(collapsed, ImGuiCond::Always);
}
pub fn set_next_window_collapsed_opts(collapsed: bool, set_cond: ImGuiCond) {
ImGui::_set_next_window_collapsed_opts(collapsed, set_cond as i32);
}
pub fn set_window_pos(name: &str, pos: &crate::dora::Vec2) {
ImGui::set_window_pos_opts(name, pos, ImGuiCond::Always);
}
pub fn set_window_pos_opts(name: &str, pos: &crate::dora::Vec2, set_cond: ImGuiCond) {
ImGui::_set_window_pos_opts(name, pos, set_cond as i32);
}
pub fn set_window_size(name: &str, size: &crate::dora::Vec2) {
ImGui::set_window_size_opts(name, size, ImGuiCond::Always);
}
pub fn set_window_size_opts(name: &str, size: &crate::dora::Vec2, set_cond: ImGuiCond) {
ImGui::_set_window_size_opts(name, size, set_cond as i32);
}
pub fn set_window_collapsed(name: &str, collapsed: bool) {
ImGui::set_window_collapsed_opts(name, collapsed, ImGuiCond::Always);
}
pub fn set_window_collapsed_opts(name: &str, collapsed: bool, set_cond: ImGuiCond) {
ImGui::_set_window_collapsed_opts(name, collapsed, set_cond as i32);
}
pub fn set_color_edit_options(color_edit_flags: BitFlags<ImGuiColorEditFlag>) {
ImGui::_set_color_edit_options(color_edit_flags.bits() as i32);
}
pub fn input_text(label: &str, buffer: &crate::dora::Buffer) -> bool {
ImGui::input_text_opts(label, buffer, BitFlags::default())
}
pub fn input_text_opts(
label: &str,
buffer: &crate::dora::Buffer,
input_text_flags: BitFlags<ImGuiInputTextFlag>,
) -> bool {
ImGui::_input_text_opts(label, buffer, input_text_flags.bits() as i32)
}
pub fn input_text_multiline(
label: &str,
buffer: &crate::dora::Buffer,
size: &crate::dora::Vec2,
) -> bool {
ImGui::input_text_multiline_opts(label, buffer, size, BitFlags::default())
}
pub fn input_text_multiline_opts(
label: &str,
buffer: &crate::dora::Buffer,
size: &crate::dora::Vec2,
input_text_flags: BitFlags<ImGuiInputTextFlag>,
) -> bool {
ImGui::_input_text_multiline_opts(label, buffer, size, input_text_flags.bits() as i32)
}
pub fn tree_push<C>(str_id: &str, inside: C)
where
C: FnOnce(),
{
ImGui::_tree_push(str_id);
inside();
ImGui::_tree_pop();
}
pub fn tree_node<C>(str_id: &str, text: &str, inside: C)
where
C: FnOnce(),
{
if ImGui::_tree_node(str_id, text) {
inside();
ImGui::_tree_pop();
}
}
pub fn tree_node_ex<C>(label: &str, inside: C)
where
C: FnOnce(),
{
ImGui::tree_node_ex_opts(label, BitFlags::default(), inside)
}
pub fn tree_node_ex_opts<C>(
label: &str,
tree_node_flags: BitFlags<ImGuiTreeNodeFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_tree_node_ex_opts(label, tree_node_flags.bits() as i32) {
inside();
ImGui::_tree_pop();
}
}
pub fn tree_node_ex_with_id<C>(str_id: &str, text: &str, inside: C)
where
C: FnOnce(),
{
ImGui::tree_node_ex_with_id_opts(str_id, text, BitFlags::default(), inside);
}
pub fn tree_node_ex_with_id_opts<C>(
str_id: &str,
text: &str,
tree_node_flags: BitFlags<ImGuiTreeNodeFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_tree_node_ex_with_id_opts(str_id, text, tree_node_flags.bits() as i32) {
inside();
ImGui::_tree_pop();
}
}
pub fn set_next_item_open(is_open: bool) {
ImGui::set_next_item_open_opts(is_open, ImGuiCond::Always);
}
pub fn set_next_item_open_opts(is_open: bool, set_cond: ImGuiCond) {
ImGui::_set_next_item_open_opts(is_open, set_cond as i32);
}
pub fn collapsing_header(label: &str) -> bool {
ImGui::collapsing_header_opts(label, BitFlags::default())
}
pub fn collapsing_header_opts(
label: &str,
tree_node_flags: BitFlags<ImGuiTreeNodeFlag>,
) -> bool {
ImGui::_collapsing_header_opts(label, tree_node_flags.bits() as i32)
}
pub fn selectable(label: &str) -> bool {
ImGui::selectable_opts(label, BitFlags::default())
}
pub fn selectable_opts(label: &str, selectable_flags: BitFlags<ImGuiSelectableFlag>) -> bool {
ImGui::_selectable_opts(label, selectable_flags.bits() as i32)
}
pub fn begin_popup<C>(str_id: &str, inside: C)
where
C: FnOnce(),
{
if ImGui::_begin_popup(str_id) {
inside();
ImGui::_end_popup();
}
}
pub fn begin_popup_modal<C>(name: &str, inside: C)
where
C: FnOnce(),
{
ImGui::begin_popup_modal_opts(name, BitFlags::default(), inside);
}
pub fn begin_popup_modal_opts<C>(
name: &str,
windows_flags: BitFlags<ImGuiWindowFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_begin_popup_modal_opts(name, windows_flags.bits() as i32) {
inside();
ImGui::_end_popup();
}
}
pub fn begin_popup_modal_ret<C>(
name: &str,
opened: bool,
inside: C,
) -> (bool, bool)
where
C: FnOnce(),
{
ImGui::begin_popup_modal_ret_opts(name, opened, BitFlags::default(), inside)
}
pub fn begin_popup_modal_ret_opts<C>(
name: &str,
opened: bool,
windows_flags: BitFlags<ImGuiWindowFlag>,
inside: C,
) -> (bool, bool)
where
C: FnOnce(),
{
let mut changed = false;
let mut result = false;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_bool(opened);
changed = ImGui::_begin_popup_modal_ret_opts(name, stack, windows_flags.bits() as i32);
result = stack.pop_bool().unwrap();
});
if changed {
inside();
ImGui::_end_popup();
}
(changed, result)
}
pub fn begin_popup_context_item<C>(name: &str, inside: C)
where
C: FnOnce(),
{
ImGui::begin_popup_context_item_opts(
name,
ImGuiPopupButton::MouseButtonRight,
BitFlags::default(),
inside,
);
}
pub fn begin_popup_context_item_opts<C>(
name: &str,
button: ImGuiPopupButton,
popup_flags: BitFlags<ImGuiPopupFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_begin_popup_context_item_opts(name, (button as u32 | popup_flags.bits()) as i32)
{
inside();
ImGui::_end_popup();
}
}
pub fn begin_popup_context_window<C>(name: &str, inside: C)
where
C: FnOnce(),
{
ImGui::begin_popup_context_window_opts(
name,
ImGuiPopupButton::MouseButtonRight,
BitFlags::default(),
inside,
);
}
pub fn begin_popup_context_window_opts<C>(
name: &str,
button: ImGuiPopupButton,
popup_flags: BitFlags<ImGuiPopupFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_begin_popup_context_window_opts(
name,
(button as u32 | popup_flags.bits()) as i32,
) {
inside();
ImGui::_end_popup();
}
}
pub fn begin_popup_context_void<C>(name: &str, inside: C)
where
C: FnOnce(),
{
ImGui::begin_popup_context_void_opts(
name,
ImGuiPopupButton::MouseButtonRight,
BitFlags::default(),
inside,
);
}
pub fn begin_popup_context_void_opts<C>(
name: &str,
button: ImGuiPopupButton,
popup_flags: BitFlags<ImGuiPopupFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_begin_popup_context_void_opts(name, (button as u32 | popup_flags.bits()) as i32)
{
inside();
ImGui::_end_popup();
}
}
pub fn begin_table<C>(str_id: &str, column: i32, inside: C)
where
C: FnOnce(),
{
ImGui::begin_table_opts(str_id, column, &Vec2::zero(), -1.0, BitFlags::default(), inside);
}
pub fn begin_table_opts<C>(
str_id: &str,
column: i32,
outer_size: &crate::dora::Vec2,
inner_width: f32,
table_flags: BitFlags<ImGuiTableFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_begin_table_opts(
str_id,
column,
outer_size,
inner_width,
table_flags.bits() as i32,
) {
inside();
ImGui::_end_table();
}
}
pub fn table_setup_column(label: &str, init_width_or_weight: f32) {
ImGui::table_setup_column_opts(label, init_width_or_weight, 0, BitFlags::default())
}
pub fn table_setup_column_opts(
label: &str,
init_width_or_weight: f32,
user_id: i32,
table_column_flags: BitFlags<ImGuiTableColumnFlag>,
) {
ImGui::_table_setup_column_opts(
label,
init_width_or_weight,
user_id,
table_column_flags.bits() as i32,
);
}
pub fn set_next_window_pos(pos: &crate::dora::Vec2) {
ImGui::set_next_window_pos_opts(pos, ImGuiCond::Always, &Vec2::zero());
}
pub fn set_next_window_pos_opts(
pos: &crate::dora::Vec2,
set_cond: ImGuiCond,
pivot: &crate::dora::Vec2,
) {
ImGui::_set_next_window_pos_opts(pos, set_cond as i32, pivot);
}
pub fn push_style_color<C>(col: ImGuiCol, color: &crate::dora::Color, inside: C)
where
C: FnOnce(),
{
ImGui::_push_style_color(col as i32, color);
inside();
ImGui::_pop_style_color(1);
}
pub fn push_style_float<C>(style: ImGuiStyleVar, val: f32, inside: C)
where
C: FnOnce(),
{
ImGui::_push_style_float(style as i32, val);
inside();
ImGui::_pop_style_var(1);
}
pub fn push_style_vec2<C>(style: ImGuiStyleVec2, val: &crate::dora::Vec2, inside: C)
where
C: FnOnce(),
{
ImGui::_push_style_vec2(style as i32, val);
inside();
ImGui::_pop_style_var(1);
}
pub fn color_button(desc_id: &str, col: &crate::dora::Color) -> bool {
ImGui::color_button_opts(desc_id, col, BitFlags::default(), &Vec2::zero())
}
pub fn color_button_opts(
desc_id: &str,
col: &crate::dora::Color,
color_edit_flags: BitFlags<ImGuiColorEditFlag>,
size: &crate::dora::Vec2,
) -> bool {
ImGui::_color_button_opts(desc_id, col, color_edit_flags.bits() as i32, size)
}
pub fn slider_angle_ret(
label: &str,
v: f32,
v_degrees_min: f32,
v_degrees_max: f32,
) -> (bool, f32) {
let mut changed = false;
let mut result = 0_f32;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_f32(v);
changed = ImGui::_slider_angle_ret(label, stack, v_degrees_min, v_degrees_max);
result = stack.pop_f32().unwrap();
});
(changed, result)
}
pub fn image_button(str_id: &str, clip_str: &str, size: &crate::dora::Vec2) -> bool {
ImGui::image_button_opts(str_id, clip_str, size, &Color::TRANSPARENT, &Color::WHITE)
}
pub fn table_next_row() {
ImGui::table_next_row_opts(0.0, BitFlags::default());
}
pub fn table_next_row_opts(min_row_height: f32, table_row_flags: BitFlags<ImGuiTableRowFlag>) {
ImGui::_table_next_row_opts(min_row_height, table_row_flags.bits() as i32);
}
pub fn begin_list_box<C>(label: &str, size: &crate::dora::Vec2, inside: C)
where
C: FnOnce(),
{
if ImGui::_begin_list_box(label, size) {
inside();
ImGui::_end_list_box();
}
}
pub fn begin_group<C>(inside: C)
where
C: FnOnce(),
{
ImGui::_begin_group();
inside();
ImGui::_end_group();
}
pub fn begin_disabled<C>(inside: C)
where
C: FnOnce(),
{
ImGui::_begin_disabled();
inside();
ImGui::_end_disabled();
}
pub fn begin_tooltip<C>(inside: C)
where
C: FnOnce(),
{
if ImGui::_begin_tooltip() {
inside();
ImGui::_end_tooltip();
}
}
pub fn begin_main_menu_bar<C>(inside: C)
where
C: FnOnce(),
{
if ImGui::_begin_main_menu_bar() {
inside();
ImGui::_end_main_menu_bar();
}
}
pub fn begin_menu_bar<C>(inside: C)
where
C: FnOnce(),
{
if ImGui::_begin_menu_bar() {
inside();
ImGui::_end_menu_bar();
}
}
pub fn begin_menu<C>(label: &str, enabled: bool, inside: C)
where
C: FnOnce(),
{
if ImGui::_begin_menu(label, enabled) {
inside();
ImGui::_end_menu();
}
}
pub fn push_item_width<C>(width: f32, inside: C)
where
C: FnOnce(),
{
ImGui::_push_item_width(width);
inside();
ImGui::_pop_item_width();
}
pub fn push_text_wrap_pos<C>(wrap_pos_x: f32, inside: C)
where
C: FnOnce(),
{
ImGui::_push_text_wrap_pos(wrap_pos_x);
inside();
ImGui::_pop_text_wrap_pos();
}
pub fn push_item_flag<C>(flags: BitFlags<ImGuiItemFlag>, v: bool, inside: C)
where
C: FnOnce(),
{
ImGui::_push_item_flag(flags.bits() as i32, v);
inside();
ImGui::_pop_item_flag();
}
pub fn push_id<C>(str_id: &str, inside: C)
where
C: FnOnce(),
{
ImGui::_push_id(str_id);
inside();
ImGui::_pop_id();
}
pub fn push_clip_rect<C>(
clip_rect_min: &crate::dora::Vec2,
clip_rect_max: &crate::dora::Vec2,
intersect_with_current_clip_rect: bool,
inside: C,
) where
C: FnOnce(),
{
ImGui::_push_clip_rect(clip_rect_min, clip_rect_max, intersect_with_current_clip_rect);
inside();
ImGui::_pop_clip_rect();
}
pub fn begin_tab_bar<C>(str_id: &str, inside: C)
where
C: FnOnce(),
{
if ImGui::_begin_tab_bar(str_id) {
inside();
ImGui::_end_tab_bar();
}
}
pub fn begin_tab_bar_opts<C>(
str_id: &str,
flags: BitFlags<ImGuiTabBarFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_begin_tab_bar_opts(str_id, flags.bits() as i32) {
inside();
ImGui::_end_tab_bar();
}
}
pub fn begin_tab_item<C>(label: &str, inside: C)
where
C: FnOnce(),
{
if ImGui::_begin_tab_item(label) {
inside();
ImGui::_end_tab_item();
}
}
pub fn begin_tab_item_opts<C>(
label: &str,
flags: BitFlags<ImGuiTabItemFlag>,
inside: C,
) where
C: FnOnce(),
{
if ImGui::_begin_tab_item_opts(label, flags.bits() as i32) {
inside();
ImGui::_end_tab_item();
}
}
pub fn begin_tab_item_ret<C>(label: &str, opened: bool, inside: C) -> bool
where
C: FnOnce(),
{
let mut changed = false;
let mut result = false;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_bool(opened);
result = ImGui::_begin_tab_item_ret(label, stack);
changed = stack.pop_bool().unwrap();
});
if result {
inside();
ImGui::_end_tab_item();
}
changed
}
pub fn begin_tab_item_ret_opts<C>(
label: &str,
opened: bool,
flags: BitFlags<ImGuiTabItemFlag>,
inside: C,
) -> bool
where
C: FnOnce(),
{
let mut changed = false;
let mut result = false;
IMGUI_STACK.with_borrow_mut(|stack| {
stack.push_bool(opened);
result = ImGui::_begin_tab_item_ret_opts(label, stack, flags.bits() as i32);
changed = stack.pop_bool().unwrap();
});
if result {
inside();
ImGui::_end_tab_item();
}
changed
}
pub fn tab_item_button_opts(label: &str, flags: BitFlags<ImGuiTabItemFlag>) -> bool {
ImGui::_tab_item_button_opts(label, flags.bits() as i32)
}
}
#[bitflags]
#[repr(u32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum NvgImageFlag {
GenerateMipmaps = 1 << 0,
RepeatX = 1 << 1,
RepeatY = 1 << 2,
FlipY = 1 << 3,
Premultiplied = 1 << 4,
Nearest = 1 << 5,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum NvgLineCap {
Butt = 0,
Round = 1,
Square = 2,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum NvgLineJoin {
Round = 1,
Bevel = 3,
Miter = 4,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum NvgWinding {
CCW = 1,
CW = 2,
}
impl NvgWinding {
pub const SOLID: NvgWinding = NvgWinding::CCW;
pub const HOLE: NvgWinding = NvgWinding::CW;
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum NvgArcDir {
CCW = 1,
CW = 2,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum NvgHAlign {
Left = 1 << 0,
Center = 1 << 1,
Right = 1 << 2,
}
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum NvgVAlign {
Top = 1 << 3,
Middle = 1 << 4,
Bottom = 1 << 5,
BaseLine = 1 << 6,
}
impl Nvg {
pub fn create_image(
w: i32,
h: i32,
filename: &str,
image_flags: BitFlags<NvgImageFlag>,
) -> i32 {
Nvg::_create_image(w, h, filename, image_flags.bits() as i32)
}
pub fn line_cap(cap: NvgLineCap) {
Nvg::_line_cap(cap as i32);
}
pub fn line_join(join: NvgLineJoin) {
Nvg::_line_join(join as i32);
}
pub fn path_winding(winding: NvgWinding) {
Nvg::_path_winding(winding as i32);
}
pub fn arc(x: f32, y: f32, r: f32, a0: f32, a1: f32, dir: NvgArcDir) {
Nvg::_arc(x, y, r, a0, a1, dir as i32);
}
pub fn text_align(h_align: NvgHAlign, v_align: NvgVAlign) {
Nvg::_text_align(h_align as i32, v_align as i32);
}
}
extern "C" {
fn math_abs(v: f64) -> f64;
fn math_acos(v: f32) -> f32;
fn math_asin(v: f32) -> f32;
fn math_atan(v: f32) -> f32;
fn math_atan2(y: f32, x: f32) -> f32;
fn math_ceil(v: f32) -> f32;
fn math_cos(v: f32) -> f32;
fn math_deg(v: f32) -> f32;
fn math_exp(v: f32) -> f32;
fn math_floor(v: f32) -> f32;
fn math_fmod(x: f32, y: f32) -> f32;
fn math_log(v: f32) -> f32;
fn math_rad(v: f32) -> f32;
fn math_sin(v: f32) -> f32;
fn math_sqrt(v: f32) -> f32;
fn math_tan(v: f32) -> f32;
}
pub struct Math {}
impl Math {
pub const PI: f32 = std::f32::consts::PI;
pub fn abs(v: f64) -> f64 {
unsafe { math_abs(v) }
}
pub fn acos(v: f32) -> f32 {
unsafe { math_acos(v) }
}
pub fn asin(v: f32) -> f32 {
unsafe { math_asin(v) }
}
pub fn atan(v: f32) -> f32 {
unsafe { math_atan(v) }
}
pub fn atan2(y: f32, x: f32) -> f32 {
unsafe { math_atan2(y, x) }
}
pub fn ceil(v: f32) -> f32 {
unsafe { math_ceil(v) }
}
pub fn cos(v: f32) -> f32 {
unsafe { math_cos(v) }
}
pub fn deg(v: f32) -> f32 {
unsafe { math_deg(v) }
}
pub fn exp(v: f32) -> f32 {
unsafe { math_exp(v) }
}
pub fn floor(v: f32) -> f32 {
unsafe { math_floor(v) }
}
pub fn fmod(x: f32, y: f32) -> f32 {
unsafe { math_fmod(x, y) }
}
pub fn log(v: f32) -> f32 {
unsafe { math_log(v) }
}
pub fn rad(v: f32) -> f32 {
unsafe { math_rad(v) }
}
pub fn sin(v: f32) -> f32 {
unsafe { math_sin(v) }
}
pub fn sqrt(v: f32) -> f32 {
unsafe { math_sqrt(v) }
}
pub fn tan(v: f32) -> f32 {
unsafe { math_tan(v) }
}
}
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
enum State {
Halted,
Running,
}
pub struct Coroutine {
state: State,
}
impl Coroutine {
pub fn waiter<'a>(&'a mut self) -> Waiter<'a> {
Waiter { co: self }
}
}
pub struct Waiter<'a> {
co: &'a mut Coroutine,
}
impl<'a> Future for Waiter<'a> {
type Output = ();
fn poll(mut self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Self::Output> {
match self.co.state {
State::Halted => {
self.co.state = State::Running;
Poll::Ready(())
}
State::Running => {
self.co.state = State::Halted;
Poll::Pending
}
}
}
}
use std::task::{RawWaker, RawWakerVTable, Waker};
fn create_waker() -> Waker {
unsafe { Waker::from_raw(RAW_WAKER) }
}
const RAW_WAKER: RawWaker = RawWaker::new(std::ptr::null(), &VTABLE);
const VTABLE: RawWakerVTable = RawWakerVTable::new(clone, wake, wake_by_ref, drop);
unsafe fn clone(_: *const ()) -> RawWaker {
RAW_WAKER
}
unsafe fn wake(_: *const ()) {}
unsafe fn wake_by_ref(_: *const ()) {}
unsafe fn drop(_: *const ()) {}
struct Executor {
co: Pin<Box<dyn Future<Output = ()>>>,
}
impl Executor {
fn new<C, F>(closure: C) -> Self
where
F: Future<Output = ()> + 'static,
C: FnOnce(Coroutine) -> F,
{
let co = Coroutine { state: State::Running };
Executor { co: Box::pin(closure(co)) }
}
fn update(&mut self) -> bool {
let waker = create_waker();
let mut context = Context::from_waker(&waker);
match self.co.as_mut().poll(&mut context) {
Poll::Pending => false,
Poll::Ready(()) => true,
}
}
}
pub fn once<C, F>(closure: C) -> Box<dyn FnMut(f64) -> bool>
where
F: Future<Output = ()> + 'static,
C: FnOnce(Coroutine) -> F,
{
let mut executor = Executor::new(closure);
Box::new(move |_| executor.update())
}
pub fn thread<C, F>(closure: C)
where
F: Future<Output = ()> + 'static,
C: FnOnce(Coroutine) -> F,
{
let mut executor = Executor::new(closure);
Director::schedule_posted(Box::new(move |_| executor.update()));
}
#[macro_export]
macro_rules! sleep {
($co:expr, $time:expr) => {{
let total = $time;
let mut time: f32 = 0.0;
while time <= total {
time += dora_ssr::App::get_delta_time() as f32;
$co.waiter().await;
}
}};
}
#[macro_export]
macro_rules! cycle {
($co:expr, $time:expr, $closure:expr) => {{
let total = $time;
let mut time: f32 = 0.0;
loop {
$closure(f32::min(time / $time, 1.0));
if time >= total {
break;
}
$co.waiter().await;
time += dora_ssr::App::get_delta_time() as f32;
}
}};
}
#[macro_export]
macro_rules! wait {
($co:expr, $condition:expr) => {
while !$condition {
$co.waiter().await;
}
};
}