ranma 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Cargo.lock +5571 -0
- data/Cargo.toml +3 -0
- data/LICENSE +21 -0
- data/README.md +293 -0
- data/ext/ranma/Cargo.toml +23 -0
- data/ext/ranma/extconf.rb +4 -0
- data/ext/ranma/src/app.rs +231 -0
- data/ext/ranma/src/blit.wgsl +32 -0
- data/ext/ranma/src/clipboard.rs +57 -0
- data/ext/ranma/src/dpi.rs +227 -0
- data/ext/ranma/src/event_loop.rs +145 -0
- data/ext/ranma/src/events.rs +305 -0
- data/ext/ranma/src/hotkey.rs +245 -0
- data/ext/ranma/src/ime.rs +318 -0
- data/ext/ranma/src/lib.rs +42 -0
- data/ext/ranma/src/menu.rs +588 -0
- data/ext/ranma/src/monitor.rs +149 -0
- data/ext/ranma/src/painter.rs +1082 -0
- data/ext/ranma/src/proxy.rs +34 -0
- data/ext/ranma/src/surface.rs +389 -0
- data/ext/ranma/src/theme.rs +20 -0
- data/ext/ranma/src/tray.rs +251 -0
- data/ext/ranma/src/webview.rs +334 -0
- data/ext/ranma/src/window.rs +691 -0
- data/ext/ranma/src/window_store.rs +81 -0
- data/lib/ranma/version.rb +3 -0
- data/lib/ranma.rb +61 -0
- metadata +86 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
use magnus::{function, method, prelude::*, Error, Ruby};
|
|
2
|
+
|
|
3
|
+
#[magnus::wrap(class = "Ranma::PhysicalSize", free_immediately, size)]
|
|
4
|
+
#[derive(Clone, Copy, Debug)]
|
|
5
|
+
pub struct RbPhysicalSize {
|
|
6
|
+
pub width: u32,
|
|
7
|
+
pub height: u32,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
impl RbPhysicalSize {
|
|
11
|
+
pub fn new(width: u32, height: u32) -> Self {
|
|
12
|
+
Self { width, height }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
pub fn width(&self) -> u32 {
|
|
16
|
+
self.width
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
pub fn height(&self) -> u32 {
|
|
20
|
+
self.height
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pub fn to_a(&self) -> (u32, u32) {
|
|
24
|
+
(self.width, self.height)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub fn inspect(&self) -> String {
|
|
28
|
+
format!("#<Ranma::PhysicalSize {}x{}>", self.width, self.height)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
pub fn to_s(&self) -> String {
|
|
32
|
+
format!("{}x{}", self.width, self.height)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
impl From<tao::dpi::PhysicalSize<u32>> for RbPhysicalSize {
|
|
37
|
+
fn from(size: tao::dpi::PhysicalSize<u32>) -> Self {
|
|
38
|
+
Self {
|
|
39
|
+
width: size.width,
|
|
40
|
+
height: size.height,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
impl From<RbPhysicalSize> for tao::dpi::PhysicalSize<u32> {
|
|
46
|
+
fn from(size: RbPhysicalSize) -> Self {
|
|
47
|
+
tao::dpi::PhysicalSize::new(size.width, size.height)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
#[magnus::wrap(class = "Ranma::LogicalSize", free_immediately, size)]
|
|
52
|
+
#[derive(Clone, Copy, Debug)]
|
|
53
|
+
pub struct RbLogicalSize {
|
|
54
|
+
pub width: f64,
|
|
55
|
+
pub height: f64,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
impl RbLogicalSize {
|
|
59
|
+
pub fn new(width: f64, height: f64) -> Self {
|
|
60
|
+
Self { width, height }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
pub fn width(&self) -> f64 {
|
|
64
|
+
self.width
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pub fn height(&self) -> f64 {
|
|
68
|
+
self.height
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
pub fn to_a(&self) -> (f64, f64) {
|
|
72
|
+
(self.width, self.height)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
pub fn inspect(&self) -> String {
|
|
76
|
+
format!("#<Ranma::LogicalSize {}x{}>", self.width, self.height)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
pub fn to_s(&self) -> String {
|
|
80
|
+
format!("{}x{}", self.width, self.height)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
impl From<tao::dpi::LogicalSize<f64>> for RbLogicalSize {
|
|
85
|
+
fn from(size: tao::dpi::LogicalSize<f64>) -> Self {
|
|
86
|
+
Self {
|
|
87
|
+
width: size.width,
|
|
88
|
+
height: size.height,
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
impl From<RbLogicalSize> for tao::dpi::LogicalSize<f64> {
|
|
94
|
+
fn from(size: RbLogicalSize) -> Self {
|
|
95
|
+
tao::dpi::LogicalSize::new(size.width, size.height)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
#[magnus::wrap(class = "Ranma::PhysicalPosition", free_immediately, size)]
|
|
100
|
+
#[derive(Clone, Copy, Debug)]
|
|
101
|
+
pub struct RbPhysicalPosition {
|
|
102
|
+
pub x: i32,
|
|
103
|
+
pub y: i32,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
impl RbPhysicalPosition {
|
|
107
|
+
pub fn new(x: i32, y: i32) -> Self {
|
|
108
|
+
Self { x, y }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
pub fn x(&self) -> i32 {
|
|
112
|
+
self.x
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
pub fn y(&self) -> i32 {
|
|
116
|
+
self.y
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
pub fn to_a(&self) -> (i32, i32) {
|
|
120
|
+
(self.x, self.y)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
pub fn inspect(&self) -> String {
|
|
124
|
+
format!("#<Ranma::PhysicalPosition ({}, {})>", self.x, self.y)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
pub fn to_s(&self) -> String {
|
|
128
|
+
format!("({}, {})", self.x, self.y)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
impl From<tao::dpi::PhysicalPosition<i32>> for RbPhysicalPosition {
|
|
133
|
+
fn from(pos: tao::dpi::PhysicalPosition<i32>) -> Self {
|
|
134
|
+
Self { x: pos.x, y: pos.y }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
impl From<RbPhysicalPosition> for tao::dpi::PhysicalPosition<i32> {
|
|
139
|
+
fn from(pos: RbPhysicalPosition) -> Self {
|
|
140
|
+
tao::dpi::PhysicalPosition::new(pos.x, pos.y)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#[magnus::wrap(class = "Ranma::LogicalPosition", free_immediately, size)]
|
|
145
|
+
#[derive(Clone, Copy, Debug)]
|
|
146
|
+
pub struct RbLogicalPosition {
|
|
147
|
+
pub x: f64,
|
|
148
|
+
pub y: f64,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
impl RbLogicalPosition {
|
|
152
|
+
pub fn new(x: f64, y: f64) -> Self {
|
|
153
|
+
Self { x, y }
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
pub fn x(&self) -> f64 {
|
|
157
|
+
self.x
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
pub fn y(&self) -> f64 {
|
|
161
|
+
self.y
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
pub fn to_a(&self) -> (f64, f64) {
|
|
165
|
+
(self.x, self.y)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
pub fn inspect(&self) -> String {
|
|
169
|
+
format!("#<Ranma::LogicalPosition ({}, {})>", self.x, self.y)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
pub fn to_s(&self) -> String {
|
|
173
|
+
format!("({}, {})", self.x, self.y)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
impl From<tao::dpi::LogicalPosition<f64>> for RbLogicalPosition {
|
|
178
|
+
fn from(pos: tao::dpi::LogicalPosition<f64>) -> Self {
|
|
179
|
+
Self { x: pos.x, y: pos.y }
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
impl From<RbLogicalPosition> for tao::dpi::LogicalPosition<f64> {
|
|
184
|
+
fn from(pos: RbLogicalPosition) -> Self {
|
|
185
|
+
tao::dpi::LogicalPosition::new(pos.x, pos.y)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
pub fn define_dpi_classes(ruby: &Ruby, module: &magnus::RModule) -> Result<(), Error> {
|
|
190
|
+
// PhysicalSize
|
|
191
|
+
let physical_size = module.define_class("PhysicalSize", ruby.class_object())?;
|
|
192
|
+
physical_size.define_singleton_method("new", function!(RbPhysicalSize::new, 2))?;
|
|
193
|
+
physical_size.define_method("width", method!(RbPhysicalSize::width, 0))?;
|
|
194
|
+
physical_size.define_method("height", method!(RbPhysicalSize::height, 0))?;
|
|
195
|
+
physical_size.define_method("to_a", method!(RbPhysicalSize::to_a, 0))?;
|
|
196
|
+
physical_size.define_method("inspect", method!(RbPhysicalSize::inspect, 0))?;
|
|
197
|
+
physical_size.define_method("to_s", method!(RbPhysicalSize::to_s, 0))?;
|
|
198
|
+
|
|
199
|
+
// LogicalSize
|
|
200
|
+
let logical_size = module.define_class("LogicalSize", ruby.class_object())?;
|
|
201
|
+
logical_size.define_singleton_method("new", function!(RbLogicalSize::new, 2))?;
|
|
202
|
+
logical_size.define_method("width", method!(RbLogicalSize::width, 0))?;
|
|
203
|
+
logical_size.define_method("height", method!(RbLogicalSize::height, 0))?;
|
|
204
|
+
logical_size.define_method("to_a", method!(RbLogicalSize::to_a, 0))?;
|
|
205
|
+
logical_size.define_method("inspect", method!(RbLogicalSize::inspect, 0))?;
|
|
206
|
+
logical_size.define_method("to_s", method!(RbLogicalSize::to_s, 0))?;
|
|
207
|
+
|
|
208
|
+
// PhysicalPosition
|
|
209
|
+
let physical_position = module.define_class("PhysicalPosition", ruby.class_object())?;
|
|
210
|
+
physical_position.define_singleton_method("new", function!(RbPhysicalPosition::new, 2))?;
|
|
211
|
+
physical_position.define_method("x", method!(RbPhysicalPosition::x, 0))?;
|
|
212
|
+
physical_position.define_method("y", method!(RbPhysicalPosition::y, 0))?;
|
|
213
|
+
physical_position.define_method("to_a", method!(RbPhysicalPosition::to_a, 0))?;
|
|
214
|
+
physical_position.define_method("inspect", method!(RbPhysicalPosition::inspect, 0))?;
|
|
215
|
+
physical_position.define_method("to_s", method!(RbPhysicalPosition::to_s, 0))?;
|
|
216
|
+
|
|
217
|
+
// LogicalPosition
|
|
218
|
+
let logical_position = module.define_class("LogicalPosition", ruby.class_object())?;
|
|
219
|
+
logical_position.define_singleton_method("new", function!(RbLogicalPosition::new, 2))?;
|
|
220
|
+
logical_position.define_method("x", method!(RbLogicalPosition::x, 0))?;
|
|
221
|
+
logical_position.define_method("y", method!(RbLogicalPosition::y, 0))?;
|
|
222
|
+
logical_position.define_method("to_a", method!(RbLogicalPosition::to_a, 0))?;
|
|
223
|
+
logical_position.define_method("inspect", method!(RbLogicalPosition::inspect, 0))?;
|
|
224
|
+
logical_position.define_method("to_s", method!(RbLogicalPosition::to_s, 0))?;
|
|
225
|
+
|
|
226
|
+
Ok(())
|
|
227
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
use std::cell::RefCell;
|
|
2
|
+
use magnus::{function, method, prelude::*, block::Proc, Error, Ruby, RHash, RArray, Symbol, Value, TryConvert, IntoValue};
|
|
3
|
+
use tao::event_loop::{ControlFlow, EventLoop, EventLoopWindowTarget};
|
|
4
|
+
use tao::platform::run_return::EventLoopExtRunReturn;
|
|
5
|
+
use crate::events::convert_event;
|
|
6
|
+
use crate::window::{RbWindow, create_window_from_hash};
|
|
7
|
+
use crate::monitor::RbMonitorHandle;
|
|
8
|
+
|
|
9
|
+
#[magnus::wrap(class = "Ranma::EventLoopTarget", free_immediately, size)]
|
|
10
|
+
pub struct RbEventLoopTarget {
|
|
11
|
+
ptr: RefCell<Option<*const EventLoopWindowTarget<()>>>,
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
unsafe impl Send for RbEventLoopTarget {}
|
|
15
|
+
|
|
16
|
+
impl RbEventLoopTarget {
|
|
17
|
+
pub fn new(target: &EventLoopWindowTarget<()>) -> Self {
|
|
18
|
+
Self {
|
|
19
|
+
ptr: RefCell::new(Some(target as *const _)),
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pub fn invalidate(&self) {
|
|
24
|
+
*self.ptr.borrow_mut() = None;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fn with_target<F, R>(&self, f: F) -> Result<R, Error>
|
|
28
|
+
where
|
|
29
|
+
F: FnOnce(&EventLoopWindowTarget<()>) -> R,
|
|
30
|
+
{
|
|
31
|
+
let borrow = self.ptr.borrow();
|
|
32
|
+
match *borrow {
|
|
33
|
+
Some(ptr) => Ok(f(unsafe { &*ptr })),
|
|
34
|
+
None => Err(Error::new(
|
|
35
|
+
unsafe { Ruby::get_unchecked() }.exception_runtime_error(),
|
|
36
|
+
"EventLoopTarget is only valid inside the Ranma.run callback",
|
|
37
|
+
)),
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
pub fn create_window(&self, opts: Option<RHash>) -> Result<RbWindow, Error> {
|
|
42
|
+
let ruby = unsafe { Ruby::get_unchecked() };
|
|
43
|
+
let borrow = self.ptr.borrow();
|
|
44
|
+
match *borrow {
|
|
45
|
+
Some(ptr) => {
|
|
46
|
+
let target = unsafe { &*ptr };
|
|
47
|
+
create_window_from_hash(&ruby, target, opts)
|
|
48
|
+
}
|
|
49
|
+
None => Err(Error::new(
|
|
50
|
+
ruby.exception_runtime_error(),
|
|
51
|
+
"EventLoopTarget is only valid inside the Ranma.run callback",
|
|
52
|
+
)),
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pub fn available_monitors(&self) -> Result<RArray, Error> {
|
|
57
|
+
let ruby = unsafe { Ruby::get_unchecked() };
|
|
58
|
+
self.with_target(|t| {
|
|
59
|
+
let arr = ruby.ary_new();
|
|
60
|
+
for m in t.available_monitors() {
|
|
61
|
+
let _ = arr.push(RbMonitorHandle::new(m));
|
|
62
|
+
}
|
|
63
|
+
arr
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pub fn primary_monitor(&self) -> Result<Option<RbMonitorHandle>, Error> {
|
|
68
|
+
self.with_target(|t| {
|
|
69
|
+
t.primary_monitor().map(|m| RbMonitorHandle::new(m))
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn parse_control_flow(value: Value) -> ControlFlow {
|
|
75
|
+
if value.is_nil() {
|
|
76
|
+
return ControlFlow::Wait;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if let Ok(sym) = Symbol::try_convert(value) {
|
|
80
|
+
let name: String = sym.funcall("to_s", ()).unwrap_or_default();
|
|
81
|
+
return match name.as_str() {
|
|
82
|
+
"wait" => ControlFlow::Wait,
|
|
83
|
+
"poll" => ControlFlow::Poll,
|
|
84
|
+
"exit" => ControlFlow::Exit,
|
|
85
|
+
_ => ControlFlow::Wait,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if let Ok(arr) = <(Symbol, i32)>::try_convert(value) {
|
|
90
|
+
let name: String = arr.0.funcall("to_s", ()).unwrap_or_default();
|
|
91
|
+
if name == "exit" {
|
|
92
|
+
return ControlFlow::ExitWithCode(arr.1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
ControlFlow::Wait
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
pub fn ranma_run(callback: Proc) -> Result<i32, Error> {
|
|
100
|
+
let mut event_loop = EventLoop::new();
|
|
101
|
+
|
|
102
|
+
let exit_code = event_loop.run_return(|event, target, control_flow| {
|
|
103
|
+
let ruby = unsafe { Ruby::get_unchecked() };
|
|
104
|
+
|
|
105
|
+
*control_flow = ControlFlow::Wait;
|
|
106
|
+
|
|
107
|
+
let rb_event = match convert_event(&ruby, &event) {
|
|
108
|
+
Some(e) => e,
|
|
109
|
+
None => return,
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
let rb_target = RbEventLoopTarget::new(target);
|
|
113
|
+
let rb_target_value = rb_target.into_value_with(&ruby);
|
|
114
|
+
|
|
115
|
+
let result = callback.call::<_, Value>((rb_event, rb_target_value));
|
|
116
|
+
|
|
117
|
+
// Invalidate the target so it can't be used outside the callback
|
|
118
|
+
if let Ok(target_ref) = <&RbEventLoopTarget>::try_convert(rb_target_value) {
|
|
119
|
+
target_ref.invalidate();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
match result {
|
|
123
|
+
Ok(val) => {
|
|
124
|
+
*control_flow = parse_control_flow(val);
|
|
125
|
+
}
|
|
126
|
+
Err(e) => {
|
|
127
|
+
eprintln!("Ranma: Error in event callback: {}", e);
|
|
128
|
+
*control_flow = ControlFlow::ExitWithCode(1);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
Ok(exit_code)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
pub fn define_event_loop(ruby: &Ruby, module: &magnus::RModule) -> Result<(), Error> {
|
|
137
|
+
module.define_module_function("run", function!(ranma_run, 1))?;
|
|
138
|
+
|
|
139
|
+
let target_class = module.define_class("EventLoopTarget", ruby.class_object())?;
|
|
140
|
+
target_class.define_method("create_window", method!(RbEventLoopTarget::create_window, 1))?;
|
|
141
|
+
target_class.define_method("available_monitors", method!(RbEventLoopTarget::available_monitors, 0))?;
|
|
142
|
+
target_class.define_method("primary_monitor", method!(RbEventLoopTarget::primary_monitor, 0))?;
|
|
143
|
+
|
|
144
|
+
Ok(())
|
|
145
|
+
}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
use magnus::{Ruby, RHash, Symbol};
|
|
2
|
+
use tao::event::{Event, WindowEvent, StartCause, DeviceEvent, ElementState, MouseButton, TouchPhase, MouseScrollDelta};
|
|
3
|
+
use tao::keyboard::KeyCode;
|
|
4
|
+
|
|
5
|
+
fn sym(ruby: &Ruby, name: &str) -> Symbol {
|
|
6
|
+
ruby.sym_new(name).into()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
pub fn start_cause_to_symbol(ruby: &Ruby, cause: &StartCause) -> Symbol {
|
|
10
|
+
match cause {
|
|
11
|
+
StartCause::ResumeTimeReached { .. } => sym(ruby, "resume_time_reached"),
|
|
12
|
+
StartCause::WaitCancelled { .. } => sym(ruby, "wait_cancelled"),
|
|
13
|
+
StartCause::Poll => sym(ruby, "poll"),
|
|
14
|
+
StartCause::Init => sym(ruby, "init"),
|
|
15
|
+
_ => sym(ruby, "unknown"),
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
pub fn element_state_to_symbol(ruby: &Ruby, state: &ElementState) -> Symbol {
|
|
20
|
+
match state {
|
|
21
|
+
ElementState::Pressed => sym(ruby, "pressed"),
|
|
22
|
+
ElementState::Released => sym(ruby, "released"),
|
|
23
|
+
_ => sym(ruby, "unknown"),
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pub fn mouse_button_to_symbol(ruby: &Ruby, button: &MouseButton) -> Symbol {
|
|
28
|
+
match button {
|
|
29
|
+
MouseButton::Left => sym(ruby, "left"),
|
|
30
|
+
MouseButton::Right => sym(ruby, "right"),
|
|
31
|
+
MouseButton::Middle => sym(ruby, "middle"),
|
|
32
|
+
MouseButton::Other(n) => sym(ruby, &format!("other_{}", n)),
|
|
33
|
+
_ => sym(ruby, "unknown"),
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
pub fn key_code_to_symbol(ruby: &Ruby, key: &KeyCode) -> Symbol {
|
|
38
|
+
let name = match key {
|
|
39
|
+
KeyCode::KeyA => "a",
|
|
40
|
+
KeyCode::KeyB => "b",
|
|
41
|
+
KeyCode::KeyC => "c",
|
|
42
|
+
KeyCode::KeyD => "d",
|
|
43
|
+
KeyCode::KeyE => "e",
|
|
44
|
+
KeyCode::KeyF => "f",
|
|
45
|
+
KeyCode::KeyG => "g",
|
|
46
|
+
KeyCode::KeyH => "h",
|
|
47
|
+
KeyCode::KeyI => "i",
|
|
48
|
+
KeyCode::KeyJ => "j",
|
|
49
|
+
KeyCode::KeyK => "k",
|
|
50
|
+
KeyCode::KeyL => "l",
|
|
51
|
+
KeyCode::KeyM => "m",
|
|
52
|
+
KeyCode::KeyN => "n",
|
|
53
|
+
KeyCode::KeyO => "o",
|
|
54
|
+
KeyCode::KeyP => "p",
|
|
55
|
+
KeyCode::KeyQ => "q",
|
|
56
|
+
KeyCode::KeyR => "r",
|
|
57
|
+
KeyCode::KeyS => "s",
|
|
58
|
+
KeyCode::KeyT => "t",
|
|
59
|
+
KeyCode::KeyU => "u",
|
|
60
|
+
KeyCode::KeyV => "v",
|
|
61
|
+
KeyCode::KeyW => "w",
|
|
62
|
+
KeyCode::KeyX => "x",
|
|
63
|
+
KeyCode::KeyY => "y",
|
|
64
|
+
KeyCode::KeyZ => "z",
|
|
65
|
+
KeyCode::Digit0 => "0",
|
|
66
|
+
KeyCode::Digit1 => "1",
|
|
67
|
+
KeyCode::Digit2 => "2",
|
|
68
|
+
KeyCode::Digit3 => "3",
|
|
69
|
+
KeyCode::Digit4 => "4",
|
|
70
|
+
KeyCode::Digit5 => "5",
|
|
71
|
+
KeyCode::Digit6 => "6",
|
|
72
|
+
KeyCode::Digit7 => "7",
|
|
73
|
+
KeyCode::Digit8 => "8",
|
|
74
|
+
KeyCode::Digit9 => "9",
|
|
75
|
+
KeyCode::Escape => "escape",
|
|
76
|
+
KeyCode::F1 => "f1",
|
|
77
|
+
KeyCode::F2 => "f2",
|
|
78
|
+
KeyCode::F3 => "f3",
|
|
79
|
+
KeyCode::F4 => "f4",
|
|
80
|
+
KeyCode::F5 => "f5",
|
|
81
|
+
KeyCode::F6 => "f6",
|
|
82
|
+
KeyCode::F7 => "f7",
|
|
83
|
+
KeyCode::F8 => "f8",
|
|
84
|
+
KeyCode::F9 => "f9",
|
|
85
|
+
KeyCode::F10 => "f10",
|
|
86
|
+
KeyCode::F11 => "f11",
|
|
87
|
+
KeyCode::F12 => "f12",
|
|
88
|
+
KeyCode::Backspace => "backspace",
|
|
89
|
+
KeyCode::Tab => "tab",
|
|
90
|
+
KeyCode::Enter => "enter",
|
|
91
|
+
KeyCode::Space => "space",
|
|
92
|
+
KeyCode::ArrowUp => "up",
|
|
93
|
+
KeyCode::ArrowDown => "down",
|
|
94
|
+
KeyCode::ArrowLeft => "left",
|
|
95
|
+
KeyCode::ArrowRight => "right",
|
|
96
|
+
KeyCode::ShiftLeft => "left_shift",
|
|
97
|
+
KeyCode::ShiftRight => "right_shift",
|
|
98
|
+
KeyCode::ControlLeft => "left_control",
|
|
99
|
+
KeyCode::ControlRight => "right_control",
|
|
100
|
+
KeyCode::AltLeft => "left_alt",
|
|
101
|
+
KeyCode::AltRight => "right_alt",
|
|
102
|
+
KeyCode::SuperLeft => "left_super",
|
|
103
|
+
KeyCode::SuperRight => "right_super",
|
|
104
|
+
KeyCode::Delete => "delete",
|
|
105
|
+
KeyCode::Home => "home",
|
|
106
|
+
KeyCode::End => "end",
|
|
107
|
+
KeyCode::PageUp => "page_up",
|
|
108
|
+
KeyCode::PageDown => "page_down",
|
|
109
|
+
KeyCode::Insert => "insert",
|
|
110
|
+
KeyCode::CapsLock => "caps_lock",
|
|
111
|
+
KeyCode::NumLock => "num_lock",
|
|
112
|
+
KeyCode::ScrollLock => "scroll_lock",
|
|
113
|
+
KeyCode::PrintScreen => "print_screen",
|
|
114
|
+
KeyCode::Pause => "pause",
|
|
115
|
+
KeyCode::Minus => "minus",
|
|
116
|
+
KeyCode::Equal => "equal",
|
|
117
|
+
KeyCode::BracketLeft => "left_bracket",
|
|
118
|
+
KeyCode::BracketRight => "right_bracket",
|
|
119
|
+
KeyCode::Backslash => "backslash",
|
|
120
|
+
KeyCode::Semicolon => "semicolon",
|
|
121
|
+
KeyCode::Quote => "quote",
|
|
122
|
+
KeyCode::Backquote => "backquote",
|
|
123
|
+
KeyCode::Comma => "comma",
|
|
124
|
+
KeyCode::Period => "period",
|
|
125
|
+
KeyCode::Slash => "slash",
|
|
126
|
+
_ => "unknown",
|
|
127
|
+
};
|
|
128
|
+
sym(ruby, name)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
pub fn convert_window_event<'a>(ruby: &Ruby, event: &WindowEvent<'a>) -> RHash {
|
|
132
|
+
let hash = ruby.hash_new();
|
|
133
|
+
match event {
|
|
134
|
+
WindowEvent::Resized(size) => {
|
|
135
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "resized"));
|
|
136
|
+
let _ = hash.aset(sym(ruby, "width"), size.width);
|
|
137
|
+
let _ = hash.aset(sym(ruby, "height"), size.height);
|
|
138
|
+
}
|
|
139
|
+
WindowEvent::Moved(pos) => {
|
|
140
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "moved"));
|
|
141
|
+
let _ = hash.aset(sym(ruby, "x"), pos.x);
|
|
142
|
+
let _ = hash.aset(sym(ruby, "y"), pos.y);
|
|
143
|
+
}
|
|
144
|
+
WindowEvent::CloseRequested => {
|
|
145
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "close_requested"));
|
|
146
|
+
}
|
|
147
|
+
WindowEvent::Destroyed => {
|
|
148
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "destroyed"));
|
|
149
|
+
}
|
|
150
|
+
WindowEvent::DroppedFile(path) => {
|
|
151
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "dropped_file"));
|
|
152
|
+
let _ = hash.aset(sym(ruby, "path"), path.to_string_lossy().to_string());
|
|
153
|
+
}
|
|
154
|
+
WindowEvent::HoveredFile(path) => {
|
|
155
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "hovered_file"));
|
|
156
|
+
let _ = hash.aset(sym(ruby, "path"), path.to_string_lossy().to_string());
|
|
157
|
+
}
|
|
158
|
+
WindowEvent::HoveredFileCancelled => {
|
|
159
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "hovered_file_cancelled"));
|
|
160
|
+
}
|
|
161
|
+
WindowEvent::Focused(focused) => {
|
|
162
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "focused"));
|
|
163
|
+
let _ = hash.aset(sym(ruby, "focused"), *focused);
|
|
164
|
+
}
|
|
165
|
+
WindowEvent::KeyboardInput { event, is_synthetic, .. } => {
|
|
166
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "keyboard_input"));
|
|
167
|
+
let _ = hash.aset(sym(ruby, "state"), element_state_to_symbol(ruby, &event.state));
|
|
168
|
+
let _ = hash.aset(sym(ruby, "key_code"), key_code_to_symbol(ruby, &event.physical_key));
|
|
169
|
+
let _ = hash.aset(sym(ruby, "is_synthetic"), *is_synthetic);
|
|
170
|
+
}
|
|
171
|
+
WindowEvent::CursorMoved { position, .. } => {
|
|
172
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "cursor_moved"));
|
|
173
|
+
let _ = hash.aset(sym(ruby, "x"), position.x);
|
|
174
|
+
let _ = hash.aset(sym(ruby, "y"), position.y);
|
|
175
|
+
}
|
|
176
|
+
WindowEvent::CursorEntered { .. } => {
|
|
177
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "cursor_entered"));
|
|
178
|
+
}
|
|
179
|
+
WindowEvent::CursorLeft { .. } => {
|
|
180
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "cursor_left"));
|
|
181
|
+
}
|
|
182
|
+
WindowEvent::MouseWheel { delta, phase, .. } => {
|
|
183
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "mouse_wheel"));
|
|
184
|
+
match delta {
|
|
185
|
+
MouseScrollDelta::LineDelta(x, y) => {
|
|
186
|
+
let _ = hash.aset(sym(ruby, "delta_type"), sym(ruby, "line"));
|
|
187
|
+
let _ = hash.aset(sym(ruby, "delta_x"), *x as f64);
|
|
188
|
+
let _ = hash.aset(sym(ruby, "delta_y"), *y as f64);
|
|
189
|
+
}
|
|
190
|
+
MouseScrollDelta::PixelDelta(pos) => {
|
|
191
|
+
let _ = hash.aset(sym(ruby, "delta_type"), sym(ruby, "pixel"));
|
|
192
|
+
let _ = hash.aset(sym(ruby, "delta_x"), pos.x);
|
|
193
|
+
let _ = hash.aset(sym(ruby, "delta_y"), pos.y);
|
|
194
|
+
}
|
|
195
|
+
_ => {}
|
|
196
|
+
}
|
|
197
|
+
let phase_sym = match phase {
|
|
198
|
+
TouchPhase::Started => "started",
|
|
199
|
+
TouchPhase::Moved => "moved",
|
|
200
|
+
TouchPhase::Ended => "ended",
|
|
201
|
+
TouchPhase::Cancelled => "cancelled",
|
|
202
|
+
_ => "unknown",
|
|
203
|
+
};
|
|
204
|
+
let _ = hash.aset(sym(ruby, "phase"), sym(ruby, phase_sym));
|
|
205
|
+
}
|
|
206
|
+
WindowEvent::MouseInput { state, button, .. } => {
|
|
207
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "mouse_input"));
|
|
208
|
+
let _ = hash.aset(sym(ruby, "state"), element_state_to_symbol(ruby, state));
|
|
209
|
+
let _ = hash.aset(sym(ruby, "button"), mouse_button_to_symbol(ruby, button));
|
|
210
|
+
}
|
|
211
|
+
WindowEvent::ScaleFactorChanged { scale_factor, new_inner_size } => {
|
|
212
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "scale_factor_changed"));
|
|
213
|
+
let _ = hash.aset(sym(ruby, "scale_factor"), *scale_factor);
|
|
214
|
+
let _ = hash.aset(sym(ruby, "new_width"), new_inner_size.width);
|
|
215
|
+
let _ = hash.aset(sym(ruby, "new_height"), new_inner_size.height);
|
|
216
|
+
}
|
|
217
|
+
WindowEvent::ModifiersChanged(modifiers) => {
|
|
218
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "modifiers_changed"));
|
|
219
|
+
let _ = hash.aset(sym(ruby, "shift"), modifiers.shift_key());
|
|
220
|
+
let _ = hash.aset(sym(ruby, "ctrl"), modifiers.control_key());
|
|
221
|
+
let _ = hash.aset(sym(ruby, "alt"), modifiers.alt_key());
|
|
222
|
+
let _ = hash.aset(sym(ruby, "logo"), modifiers.super_key());
|
|
223
|
+
}
|
|
224
|
+
WindowEvent::ThemeChanged(theme) => {
|
|
225
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "theme_changed"));
|
|
226
|
+
let theme_sym = match theme {
|
|
227
|
+
tao::window::Theme::Light => "light",
|
|
228
|
+
tao::window::Theme::Dark => "dark",
|
|
229
|
+
_ => "unknown",
|
|
230
|
+
};
|
|
231
|
+
let _ = hash.aset(sym(ruby, "theme"), sym(ruby, theme_sym));
|
|
232
|
+
}
|
|
233
|
+
WindowEvent::ReceivedImeText(text) => {
|
|
234
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "received_ime_text"));
|
|
235
|
+
let _ = hash.aset(sym(ruby, "text"), text.clone());
|
|
236
|
+
}
|
|
237
|
+
WindowEvent::DecorationsClick => {
|
|
238
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "decorations_click"));
|
|
239
|
+
}
|
|
240
|
+
_ => {
|
|
241
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "unknown"));
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
hash
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
pub fn convert_event<'a>(ruby: &Ruby, event: &Event<'a, ()>) -> Option<RHash> {
|
|
248
|
+
let hash = ruby.hash_new();
|
|
249
|
+
match event {
|
|
250
|
+
Event::NewEvents(cause) => {
|
|
251
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "new_events"));
|
|
252
|
+
let _ = hash.aset(sym(ruby, "cause"), start_cause_to_symbol(ruby, cause));
|
|
253
|
+
Some(hash)
|
|
254
|
+
}
|
|
255
|
+
Event::WindowEvent { window_id, event, .. } => {
|
|
256
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "window_event"));
|
|
257
|
+
let _ = hash.aset(sym(ruby, "window_id"), format!("{:?}", window_id));
|
|
258
|
+
let _ = hash.aset(sym(ruby, "event"), convert_window_event(ruby, event));
|
|
259
|
+
Some(hash)
|
|
260
|
+
}
|
|
261
|
+
Event::DeviceEvent { event, .. } => {
|
|
262
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "device_event"));
|
|
263
|
+
match event {
|
|
264
|
+
DeviceEvent::MouseMotion { delta, .. } => {
|
|
265
|
+
let inner = ruby.hash_new();
|
|
266
|
+
let _ = inner.aset(sym(ruby, "type"), sym(ruby, "mouse_motion"));
|
|
267
|
+
let _ = inner.aset(sym(ruby, "delta_x"), delta.0);
|
|
268
|
+
let _ = inner.aset(sym(ruby, "delta_y"), delta.1);
|
|
269
|
+
let _ = hash.aset(sym(ruby, "event"), inner);
|
|
270
|
+
}
|
|
271
|
+
_ => {
|
|
272
|
+
let inner = ruby.hash_new();
|
|
273
|
+
let _ = inner.aset(sym(ruby, "type"), sym(ruby, "unknown"));
|
|
274
|
+
let _ = hash.aset(sym(ruby, "event"), inner);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
Some(hash)
|
|
278
|
+
}
|
|
279
|
+
Event::MainEventsCleared => {
|
|
280
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "main_events_cleared"));
|
|
281
|
+
Some(hash)
|
|
282
|
+
}
|
|
283
|
+
Event::RedrawRequested(_window_id) => {
|
|
284
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "redraw_requested"));
|
|
285
|
+
Some(hash)
|
|
286
|
+
}
|
|
287
|
+
Event::RedrawEventsCleared => {
|
|
288
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "redraw_events_cleared"));
|
|
289
|
+
Some(hash)
|
|
290
|
+
}
|
|
291
|
+
Event::LoopDestroyed => {
|
|
292
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "loop_destroyed"));
|
|
293
|
+
Some(hash)
|
|
294
|
+
}
|
|
295
|
+
Event::Suspended => {
|
|
296
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "suspended"));
|
|
297
|
+
Some(hash)
|
|
298
|
+
}
|
|
299
|
+
Event::Resumed => {
|
|
300
|
+
let _ = hash.aset(sym(ruby, "type"), sym(ruby, "resumed"));
|
|
301
|
+
Some(hash)
|
|
302
|
+
}
|
|
303
|
+
_ => None,
|
|
304
|
+
}
|
|
305
|
+
}
|