qml 0.0.1
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/.gitignore +46 -0
- data/.rspec +2 -0
- data/.travis.yml +15 -0
- data/.yardopts +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +351 -0
- data/Rakefile +6 -0
- data/examples/assets/fonts/fontawesome-webfont.ttf +0 -0
- data/examples/fizzbuzz/fizzbuzz.rb +43 -0
- data/examples/fizzbuzz/main.qml +38 -0
- data/examples/imageprovider/imageprovider.rb +57 -0
- data/examples/imageprovider/main.qml +51 -0
- data/examples/todo/main.qml +70 -0
- data/examples/todo/todo.rb +36 -0
- data/examples/twitter/main.qml +36 -0
- data/examples/twitter/twitter.rb +55 -0
- data/ext/qml/accessclass.cpp +71 -0
- data/ext/qml/accessclass.h +19 -0
- data/ext/qml/accessobject.cpp +30 -0
- data/ext/qml/accessobject.h +22 -0
- data/ext/qml/application.cpp +54 -0
- data/ext/qml/application.h +17 -0
- data/ext/qml/common.h +18 -0
- data/ext/qml/ext_accesssupport.cpp +77 -0
- data/ext/qml/ext_accesssupport.h +42 -0
- data/ext/qml/ext_gcmarker.cpp +39 -0
- data/ext/qml/ext_gcmarker.h +27 -0
- data/ext/qml/ext_kernel.cpp +62 -0
- data/ext/qml/ext_kernel.h +11 -0
- data/ext/qml/ext_metaobject.cpp +410 -0
- data/ext/qml/ext_metaobject.h +62 -0
- data/ext/qml/ext_pluginloader.cpp +55 -0
- data/ext/qml/ext_pluginloader.h +32 -0
- data/ext/qml/ext_pointer.cpp +134 -0
- data/ext/qml/ext_pointer.h +43 -0
- data/ext/qml/ext_testutil.cpp +42 -0
- data/ext/qml/ext_testutil.h +11 -0
- data/ext/qml/extconf.rb +84 -0
- data/ext/qml/foreignclass.cpp +72 -0
- data/ext/qml/foreignclass.h +88 -0
- data/ext/qml/foreignmetaobject.cpp +345 -0
- data/ext/qml/foreignmetaobject.h +46 -0
- data/ext/qml/foreignobject.cpp +22 -0
- data/ext/qml/foreignobject.h +21 -0
- data/ext/qml/functioninfo.h +16 -0
- data/ext/qml/init.cpp +69 -0
- data/ext/qml/listmodel.cpp +112 -0
- data/ext/qml/listmodel.h +43 -0
- data/ext/qml/markable.h +12 -0
- data/ext/qml/objectdata.cpp +26 -0
- data/ext/qml/objectdata.h +20 -0
- data/ext/qml/objectgc.cpp +69 -0
- data/ext/qml/objectgc.h +28 -0
- data/ext/qml/plugins/core/applicationextension.cpp +34 -0
- data/ext/qml/plugins/core/applicationextension.h +28 -0
- data/ext/qml/plugins/core/componentextension.cpp +41 -0
- data/ext/qml/plugins/core/componentextension.h +28 -0
- data/ext/qml/plugins/core/contextextension.cpp +39 -0
- data/ext/qml/plugins/core/contextextension.h +29 -0
- data/ext/qml/plugins/core/core.pro +29 -0
- data/ext/qml/plugins/core/coreplugin.cpp +87 -0
- data/ext/qml/plugins/core/coreplugin.h +49 -0
- data/ext/qml/plugins/core/engineextension.cpp +27 -0
- data/ext/qml/plugins/core/engineextension.h +28 -0
- data/ext/qml/plugins/core/imageprovider.cpp +38 -0
- data/ext/qml/plugins/core/imageprovider.h +18 -0
- data/ext/qml/plugins/core/imagerequestpromise.cpp +19 -0
- data/ext/qml/plugins/core/imagerequestpromise.h +21 -0
- data/ext/qml/plugins/core/qmlexception.cpp +11 -0
- data/ext/qml/plugins/core/qmlexception.h +17 -0
- data/ext/qml/plugins/testutil/objectlifechecker.cpp +17 -0
- data/ext/qml/plugins/testutil/objectlifechecker.h +24 -0
- data/ext/qml/plugins/testutil/ownershiptest.cpp +26 -0
- data/ext/qml/plugins/testutil/ownershiptest.h +30 -0
- data/ext/qml/plugins/testutil/testobject.cpp +6 -0
- data/ext/qml/plugins/testutil/testobject.h +108 -0
- data/ext/qml/plugins/testutil/testobjectsubclass.cpp +10 -0
- data/ext/qml/plugins/testutil/testobjectsubclass.h +19 -0
- data/ext/qml/plugins/testutil/testutil.pro +20 -0
- data/ext/qml/plugins/testutil/testutilplugin.cpp +47 -0
- data/ext/qml/plugins/testutil/testutilplugin.h +32 -0
- data/ext/qml/qmltyperegisterer.cpp +74 -0
- data/ext/qml/qmltyperegisterer.h +30 -0
- data/ext/qml/rubyclass.cpp +94 -0
- data/ext/qml/rubyclass.h +234 -0
- data/ext/qml/rubyvalue.cpp +690 -0
- data/ext/qml/rubyvalue.h +256 -0
- data/ext/qml/signalforwarder.cpp +66 -0
- data/ext/qml/signalforwarder.h +29 -0
- data/ext/qml/util.cpp +120 -0
- data/ext/qml/util.h +101 -0
- data/ext/qml/valuereference.cpp +50 -0
- data/ext/qml/valuereference.h +22 -0
- data/ext/qml/weakvaluereference.cpp +27 -0
- data/ext/qml/weakvaluereference.h +19 -0
- data/lib/qml.rb +41 -0
- data/lib/qml/access.rb +137 -0
- data/lib/qml/application.rb +139 -0
- data/lib/qml/class_builder.rb +126 -0
- data/lib/qml/component.rb +53 -0
- data/lib/qml/context.rb +71 -0
- data/lib/qml/data.rb +2 -0
- data/lib/qml/data/array_model.rb +103 -0
- data/lib/qml/data/error.rb +5 -0
- data/lib/qml/data/list_model.rb +146 -0
- data/lib/qml/dispatchable.rb +34 -0
- data/lib/qml/dispatcher.rb +61 -0
- data/lib/qml/engine.rb +54 -0
- data/lib/qml/error_converter.rb +15 -0
- data/lib/qml/errors.rb +26 -0
- data/lib/qml/geometry.rb +3 -0
- data/lib/qml/geometry/point.rb +5 -0
- data/lib/qml/geometry/rectangle.rb +5 -0
- data/lib/qml/geometry/size.rb +5 -0
- data/lib/qml/image_provider.rb +87 -0
- data/lib/qml/meta_object.rb +20 -0
- data/lib/qml/models.rb +1 -0
- data/lib/qml/name_helper.rb +12 -0
- data/lib/qml/platform.rb +15 -0
- data/lib/qml/plugin_loader.rb +46 -0
- data/lib/qml/plugins.rb +26 -0
- data/lib/qml/qml.rb +1 -0
- data/lib/qml/qt.rb +6 -0
- data/lib/qml/qt_classes.rb +9 -0
- data/lib/qml/qt_object_base.rb +108 -0
- data/lib/qml/reactive.rb +8 -0
- data/lib/qml/reactive/bindable.rb +79 -0
- data/lib/qml/reactive/chained_signal.rb +25 -0
- data/lib/qml/reactive/error.rb +5 -0
- data/lib/qml/reactive/object.rb +278 -0
- data/lib/qml/reactive/property.rb +19 -0
- data/lib/qml/reactive/signal.rb +116 -0
- data/lib/qml/reactive/signal_spy.rb +27 -0
- data/lib/qml/reactive/signals/map_signal.rb +21 -0
- data/lib/qml/reactive/signals/merge_signal.rb +21 -0
- data/lib/qml/reactive/signals/select_signal.rb +21 -0
- data/lib/qml/reactive/simple_property.rb +17 -0
- data/lib/qml/reactive/unbound_property.rb +42 -0
- data/lib/qml/reactive/unbound_signal.rb +51 -0
- data/lib/qml/root_path.rb +3 -0
- data/lib/qml/test_util.rb +1 -0
- data/lib/qml/test_util/object_life_checker.rb +17 -0
- data/lib/qml/version.rb +3 -0
- data/lib/qml/wrappable.rb +9 -0
- data/qml.gemspec +28 -0
- data/spec/assets/testobj.qml +5 -0
- data/spec/qml/.access_spec.rb.swp +0 -0
- data/spec/qml/access_spec.rb +162 -0
- data/spec/qml/application_spec.rb +43 -0
- data/spec/qml/component_spec.rb +44 -0
- data/spec/qml/context_spec.rb +43 -0
- data/spec/qml/conversion_spec.rb +59 -0
- data/spec/qml/data/array_model_spec.rb +215 -0
- data/spec/qml/dispatchable_spec.rb +26 -0
- data/spec/qml/dispatcher_spec.rb +48 -0
- data/spec/qml/geometry/point_spec.rb +4 -0
- data/spec/qml/geometry/rectangle_spec.rb +4 -0
- data/spec/qml/geometry/size_spec.rb +4 -0
- data/spec/qml/plugin_loader_spec.rb +33 -0
- data/spec/qml/qt_object_base_spec.rb +119 -0
- data/spec/qml/reactive/object_spec.rb +273 -0
- data/spec/qml/reactive/property_spec.rb +70 -0
- data/spec/qml/reactive/signal_spec.rb +191 -0
- data/spec/qml/reactive/signal_spy_spec.rb +26 -0
- data/spec/qml/test_object_spec.rb +186 -0
- data/spec/qml_spec.rb +7 -0
- data/spec/spec_helper.rb +5 -0
- metadata +321 -0
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
#include "rubyvalue.h"
|
|
2
|
+
#include "util.h"
|
|
3
|
+
#include "ext_pointer.h"
|
|
4
|
+
#include "ext_metaobject.h"
|
|
5
|
+
#include "objectdata.h"
|
|
6
|
+
#include "accessobject.h"
|
|
7
|
+
#include "listmodel.h"
|
|
8
|
+
#include "ext_accesssupport.h"
|
|
9
|
+
#include <ruby/intern.h>
|
|
10
|
+
#define ONIG_ESCAPE_UCHAR_COLLISION
|
|
11
|
+
#include <ruby/encoding.h>
|
|
12
|
+
#include <QVariant>
|
|
13
|
+
#include <QDateTime>
|
|
14
|
+
#include <QRect>
|
|
15
|
+
#include <QSet>
|
|
16
|
+
|
|
17
|
+
namespace RubyQml {
|
|
18
|
+
|
|
19
|
+
namespace detail {
|
|
20
|
+
|
|
21
|
+
namespace {
|
|
22
|
+
|
|
23
|
+
RubyValue convertToString(RubyValue x)
|
|
24
|
+
{
|
|
25
|
+
return protect([&] {
|
|
26
|
+
if (rb_type(x) == T_SYMBOL) {
|
|
27
|
+
x = rb_sym_to_s(x);
|
|
28
|
+
}
|
|
29
|
+
return rb_convert_type(x, T_STRING, "String", "to_str");
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
struct ConverterHash
|
|
34
|
+
{
|
|
35
|
+
using FromRuby = QVariant (*)(RubyValue);
|
|
36
|
+
using ToRuby = RubyValue (*)(const QVariant &);
|
|
37
|
+
|
|
38
|
+
ConverterHash()
|
|
39
|
+
{
|
|
40
|
+
add<bool>();
|
|
41
|
+
|
|
42
|
+
add<char>();
|
|
43
|
+
add<short>();
|
|
44
|
+
add<long>();
|
|
45
|
+
add<long long>();
|
|
46
|
+
add<unsigned char>();
|
|
47
|
+
add<unsigned short>();
|
|
48
|
+
add<unsigned long>();
|
|
49
|
+
add<unsigned long long>();
|
|
50
|
+
|
|
51
|
+
add<int>();
|
|
52
|
+
add<unsigned int>();
|
|
53
|
+
|
|
54
|
+
add<float>();
|
|
55
|
+
add<double>();
|
|
56
|
+
|
|
57
|
+
add<QString>();
|
|
58
|
+
add<QByteArray>();
|
|
59
|
+
|
|
60
|
+
add<QVariant>();
|
|
61
|
+
add<QVariantList>();
|
|
62
|
+
add<QVariantHash>();
|
|
63
|
+
add<QVariantMap>();
|
|
64
|
+
|
|
65
|
+
add<QDateTime>();
|
|
66
|
+
add<QDate>();
|
|
67
|
+
|
|
68
|
+
add<QPoint>();
|
|
69
|
+
add<QPointF>();
|
|
70
|
+
add<QSize>();
|
|
71
|
+
add<QSizeF>();
|
|
72
|
+
add<QRect>();
|
|
73
|
+
add<QRectF>();
|
|
74
|
+
|
|
75
|
+
add<QObject *>();
|
|
76
|
+
add<const QMetaObject *>();
|
|
77
|
+
|
|
78
|
+
fromRubyHash[QMetaType::UnknownType] = [](RubyValue value) {
|
|
79
|
+
Q_UNUSED(value);
|
|
80
|
+
return QVariant();
|
|
81
|
+
};
|
|
82
|
+
toRubyHash[QMetaType::UnknownType] = [](const QVariant &variant) {
|
|
83
|
+
Q_UNUSED(variant);
|
|
84
|
+
return RubyValue();
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
template <typename T>
|
|
89
|
+
void add()
|
|
90
|
+
{
|
|
91
|
+
addFromRuby<T>();
|
|
92
|
+
addToRuby<T>();
|
|
93
|
+
}
|
|
94
|
+
template <typename T>
|
|
95
|
+
void addFromRuby()
|
|
96
|
+
{
|
|
97
|
+
fromRubyHash[qMetaTypeId<T>()] = [](RubyValue value) {
|
|
98
|
+
return QVariant::fromValue(value.to<T>());
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
template <typename T>
|
|
102
|
+
void addToRuby()
|
|
103
|
+
{
|
|
104
|
+
toRubyHash[qMetaTypeId<T>()] = [](const QVariant &variant) {
|
|
105
|
+
return RubyValue::from(variant.value<T>());
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
QHash<int, FromRuby> fromRubyHash;
|
|
110
|
+
QHash<int, ToRuby> toRubyHash;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
Q_GLOBAL_STATIC(ConverterHash, converterHash)
|
|
114
|
+
|
|
115
|
+
} // unnamed namespace
|
|
116
|
+
|
|
117
|
+
RubyValue Conversion<const char *>::to(const char *str)
|
|
118
|
+
{
|
|
119
|
+
return protect([&] {
|
|
120
|
+
return rb_enc_str_new(str, strlen(str), rb_utf8_encoding());
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
template <> QByteArray Conversion<QByteArray>::from(RubyValue x)
|
|
125
|
+
{
|
|
126
|
+
x = convertToString(x);
|
|
127
|
+
return QByteArray(RSTRING_PTR(VALUE(x)), RSTRING_LEN(VALUE(x)));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
template <> RubyValue Conversion<QByteArray>::to(const QByteArray &str)
|
|
131
|
+
{
|
|
132
|
+
return RubyValue::from(str.constData());
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
template <> QString Conversion<QString>::from(RubyValue x)
|
|
136
|
+
{
|
|
137
|
+
x = convertToString(x);
|
|
138
|
+
return QString::fromUtf8(RSTRING_PTR(VALUE(x)), RSTRING_LEN(VALUE(x)));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
template <> RubyValue Conversion<QString>::to(const QString &str)
|
|
142
|
+
{
|
|
143
|
+
return RubyValue::from(str.toUtf8().constData());
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
template <> QDateTime Conversion<QDateTime>::from(RubyValue time)
|
|
147
|
+
{
|
|
148
|
+
timeval at;
|
|
149
|
+
int offset;
|
|
150
|
+
protect([&] {
|
|
151
|
+
if (rb_obj_is_kind_of(time, rb_cTime)) {
|
|
152
|
+
offset = NUM2INT(rb_funcall(time, RUBYQML_INTERN("gmt_offset"), 0));
|
|
153
|
+
} else { // DateTime
|
|
154
|
+
auto dayOffset = rb_funcall(time, RUBYQML_INTERN("offset"), 0);
|
|
155
|
+
offset = NUM2INT(RRATIONAL(dayOffset)->num) * 24 * 60 * 60 / NUM2INT(RRATIONAL(dayOffset)->den);
|
|
156
|
+
time = rb_funcall(time, RUBYQML_INTERN("to_time"), 0);
|
|
157
|
+
}
|
|
158
|
+
at = rb_time_timeval(time);
|
|
159
|
+
});
|
|
160
|
+
QDateTime dateTime;
|
|
161
|
+
dateTime.setOffsetFromUtc(offset);
|
|
162
|
+
dateTime.setMSecsSinceEpoch(at.tv_sec * 1000 + at.tv_usec / 1000);
|
|
163
|
+
return dateTime;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
template <> RubyValue Conversion<QDateTime>::to(const QDateTime &dateTime) {
|
|
167
|
+
RubyValue ret;
|
|
168
|
+
protect([&] {
|
|
169
|
+
auto sec = rb_rational_new(LL2NUM(dateTime.toMSecsSinceEpoch()), INT2NUM(1000));
|
|
170
|
+
auto time = rb_time_num_new(sec, INT2NUM(dateTime.offsetFromUtc()));
|
|
171
|
+
ret = rb_funcall(time, RUBYQML_INTERN("to_datetime"), 0);
|
|
172
|
+
});
|
|
173
|
+
return ret;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
template <> QDate Conversion<QDate>::from(RubyValue x)
|
|
177
|
+
{
|
|
178
|
+
int y, m, d;
|
|
179
|
+
protect([&] {
|
|
180
|
+
y = NUM2INT(rb_funcall(x, RUBYQML_INTERN("year"), 0));
|
|
181
|
+
m = NUM2INT(rb_funcall(x, RUBYQML_INTERN("month"), 0));
|
|
182
|
+
d = NUM2INT(rb_funcall(x, RUBYQML_INTERN("day"), 0));
|
|
183
|
+
});
|
|
184
|
+
return QDate(y, m, d);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
template <> RubyValue Conversion<QDate>::to(const QDate &date)
|
|
188
|
+
{
|
|
189
|
+
static auto klass = RubyClass::fromPath("Date");
|
|
190
|
+
return protect([&] {
|
|
191
|
+
return rb_funcall(klass, RUBYQML_INTERN("new"), 3,
|
|
192
|
+
INT2NUM(date.year()), INT2NUM(date.month()), INT2NUM(date.day()));
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
template <> QPoint Conversion<QPoint>::from(RubyValue value)
|
|
197
|
+
{
|
|
198
|
+
int x, y;
|
|
199
|
+
protect([&] {
|
|
200
|
+
x = NUM2INT(rb_funcall(value, RUBYQML_INTERN("x"), 0));
|
|
201
|
+
y = NUM2INT(rb_funcall(value, RUBYQML_INTERN("y"), 0));
|
|
202
|
+
});
|
|
203
|
+
return QPoint(x, y);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
template <> RubyValue Conversion<QPoint>::to(const QPoint &point)
|
|
207
|
+
{
|
|
208
|
+
static auto klass = RubyClass::fromPath("QML::Geometry::Point");
|
|
209
|
+
return protect([&] {
|
|
210
|
+
return rb_funcall(klass, RUBYQML_INTERN("new"), 2,
|
|
211
|
+
INT2NUM(point.x()), INT2NUM(point.y()));
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
template <> QPointF Conversion<QPointF>::from(RubyValue value)
|
|
216
|
+
{
|
|
217
|
+
double x, y;
|
|
218
|
+
protect([&] {
|
|
219
|
+
x = rb_num2dbl(rb_funcall(value, RUBYQML_INTERN("x"), 0));
|
|
220
|
+
y = rb_num2dbl(rb_funcall(value, RUBYQML_INTERN("y"), 0));
|
|
221
|
+
});
|
|
222
|
+
return QPointF(x, y);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
template <> RubyValue Conversion<QPointF>::to(const QPointF &point)
|
|
226
|
+
{
|
|
227
|
+
static auto klass = RubyClass::fromPath("QML::Geometry::Point");
|
|
228
|
+
return protect([&] {
|
|
229
|
+
return rb_funcall(klass, RUBYQML_INTERN("new"), 2,
|
|
230
|
+
rb_float_new(point.x()), rb_float_new(point.y()));
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
template <> QSize Conversion<QSize>::from(RubyValue value)
|
|
235
|
+
{
|
|
236
|
+
int w, h;
|
|
237
|
+
protect([&] {
|
|
238
|
+
w = NUM2INT(rb_funcall(value, RUBYQML_INTERN("width"), 0));
|
|
239
|
+
h = NUM2INT(rb_funcall(value, RUBYQML_INTERN("height"), 0));
|
|
240
|
+
});
|
|
241
|
+
return QSize(w, h);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
template <> RubyValue Conversion<QSize>::to(const QSize &size)
|
|
245
|
+
{
|
|
246
|
+
static auto klass = RubyClass::fromPath("QML::Geometry::Size");
|
|
247
|
+
return protect([&] {
|
|
248
|
+
return rb_funcall(klass, RUBYQML_INTERN("new"), 2,
|
|
249
|
+
INT2NUM(size.width()), INT2NUM(size.height()));
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
template <> QSizeF Conversion<QSizeF>::from(RubyValue value)
|
|
254
|
+
{
|
|
255
|
+
double w, h;
|
|
256
|
+
protect([&] {
|
|
257
|
+
w = rb_num2dbl(rb_funcall(value, RUBYQML_INTERN("width"), 0));
|
|
258
|
+
h = rb_num2dbl(rb_funcall(value, RUBYQML_INTERN("height"), 0));
|
|
259
|
+
});
|
|
260
|
+
return QSizeF(w, h);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
template <> RubyValue Conversion<QSizeF>::to(const QSizeF &size)
|
|
264
|
+
{
|
|
265
|
+
static auto klass = RubyClass::fromPath("QML::Geometry::Size");
|
|
266
|
+
return protect([&] {
|
|
267
|
+
return rb_funcall(klass, RUBYQML_INTERN("new"), 2,
|
|
268
|
+
rb_float_new(size.width()), rb_float_new(size.height()));
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
template <> QRect Conversion<QRect>::from(RubyValue value)
|
|
273
|
+
{
|
|
274
|
+
int x, y, w, h;
|
|
275
|
+
protect([&] {
|
|
276
|
+
x = NUM2INT(rb_funcall(value, RUBYQML_INTERN("x"), 0));
|
|
277
|
+
y = NUM2INT(rb_funcall(value, RUBYQML_INTERN("y"), 0));
|
|
278
|
+
w = NUM2INT(rb_funcall(value, RUBYQML_INTERN("width"), 0));
|
|
279
|
+
h = NUM2INT(rb_funcall(value, RUBYQML_INTERN("height"), 0));
|
|
280
|
+
});
|
|
281
|
+
return QRect(QPoint(x, y), QSize(w, h));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
template <> RubyValue Conversion<QRect>::to(const QRect &rect)
|
|
285
|
+
{
|
|
286
|
+
static auto klass = RubyClass::fromPath("QML::Geometry::Rectangle");
|
|
287
|
+
return protect([&] {
|
|
288
|
+
return rb_funcall(klass, RUBYQML_INTERN("new"), 4,
|
|
289
|
+
INT2NUM(rect.x()), INT2NUM(rect.y()),
|
|
290
|
+
INT2NUM(rect.width()), INT2NUM(rect.height()));
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
template <> QRectF Conversion<QRectF>::from(RubyValue value)
|
|
295
|
+
{
|
|
296
|
+
double x, y, w, h;
|
|
297
|
+
protect([&] {
|
|
298
|
+
x = rb_num2dbl(rb_funcall(value, RUBYQML_INTERN("x"), 0));
|
|
299
|
+
y = rb_num2dbl(rb_funcall(value, RUBYQML_INTERN("y"), 0));
|
|
300
|
+
w = rb_num2dbl(rb_funcall(value, RUBYQML_INTERN("width"), 0));
|
|
301
|
+
h = rb_num2dbl(rb_funcall(value, RUBYQML_INTERN("height"), 0));
|
|
302
|
+
});
|
|
303
|
+
return QRectF(QPoint(x, y), QSize(w, h));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
template <> RubyValue Conversion<QRectF>::to(const QRectF &rect)
|
|
307
|
+
{
|
|
308
|
+
static auto klass = RubyClass::fromPath("QML::Geometry::Rectangle");
|
|
309
|
+
return protect([&] {
|
|
310
|
+
return rb_funcall(klass, RUBYQML_INTERN("new"), 4,
|
|
311
|
+
rb_float_new(rect.x()), rb_float_new(rect.y()),
|
|
312
|
+
rb_float_new(rect.width()), rb_float_new(rect.height()));
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
template <> QVariant Conversion<QVariant>::from(RubyValue x)
|
|
317
|
+
{
|
|
318
|
+
return x.toVariant();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
template <> RubyValue Conversion<QVariant>::to(const QVariant &variant)
|
|
322
|
+
{
|
|
323
|
+
return RubyValue::fromVariant(variant);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
template <> const QMetaObject *Conversion<const QMetaObject *>::from(RubyValue x)
|
|
327
|
+
{
|
|
328
|
+
if (x == RubyValue()) {
|
|
329
|
+
return nullptr;
|
|
330
|
+
}
|
|
331
|
+
return wrapperRubyClass<Ext::MetaObject>().unwrap(x)->metaObject();
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
template <> RubyValue Conversion<const QMetaObject *>::to(const QMetaObject *metaobj)
|
|
335
|
+
{
|
|
336
|
+
if (!metaobj) {
|
|
337
|
+
return Qnil;
|
|
338
|
+
}
|
|
339
|
+
return Ext::MetaObject::fromMetaObject(metaobj);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
} // namespace detail
|
|
343
|
+
|
|
344
|
+
Q_GLOBAL_STATIC(QSet<int>, enumeratorMetaTypes)
|
|
345
|
+
|
|
346
|
+
bool RubyValue::isKindOf(const RubyModule &module) const
|
|
347
|
+
{
|
|
348
|
+
return protect([&] {
|
|
349
|
+
return rb_obj_is_kind_of(mValue, module);
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
bool RubyValue::isConvertibleTo(int metaType) const
|
|
354
|
+
{
|
|
355
|
+
auto x = *this;
|
|
356
|
+
if (metaType == QMetaType::QVariant) {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
switch (rb_type(x)) {
|
|
360
|
+
case T_NIL:
|
|
361
|
+
return metaType == QMetaType::QObjectStar || metaType == QMetaType::type("const QMetaObject*");
|
|
362
|
+
case T_TRUE:
|
|
363
|
+
case T_FALSE:
|
|
364
|
+
return metaType == QMetaType::Bool;
|
|
365
|
+
case T_FIXNUM:
|
|
366
|
+
case T_BIGNUM:
|
|
367
|
+
switch (metaType) {
|
|
368
|
+
case QMetaType::Char:
|
|
369
|
+
case QMetaType::Short:
|
|
370
|
+
case QMetaType::Long:
|
|
371
|
+
case QMetaType::LongLong:
|
|
372
|
+
|
|
373
|
+
case QMetaType::UChar:
|
|
374
|
+
case QMetaType::UShort:
|
|
375
|
+
case QMetaType::ULong:
|
|
376
|
+
case QMetaType::ULongLong:
|
|
377
|
+
|
|
378
|
+
case QMetaType::Int:
|
|
379
|
+
case QMetaType::UInt:
|
|
380
|
+
|
|
381
|
+
case QMetaType::Float:
|
|
382
|
+
case QMetaType::Double:
|
|
383
|
+
return true;
|
|
384
|
+
default:
|
|
385
|
+
if (enumeratorMetaTypes->contains(metaType)) {
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
case T_FLOAT:
|
|
391
|
+
switch (metaType) {
|
|
392
|
+
case QMetaType::Float:
|
|
393
|
+
case QMetaType::Double:
|
|
394
|
+
return true;
|
|
395
|
+
default:
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
case T_SYMBOL:
|
|
399
|
+
case T_STRING:
|
|
400
|
+
switch (metaType) {
|
|
401
|
+
case QMetaType::QByteArray:
|
|
402
|
+
case QMetaType::QString:
|
|
403
|
+
return true;
|
|
404
|
+
default:
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
case T_ARRAY:
|
|
408
|
+
switch (metaType) {
|
|
409
|
+
case QMetaType::QVariantList:
|
|
410
|
+
return true;
|
|
411
|
+
default:
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
case T_HASH:
|
|
415
|
+
switch (metaType) {
|
|
416
|
+
case QMetaType::QVariantHash:
|
|
417
|
+
case QMetaType::QVariantMap:
|
|
418
|
+
return true;
|
|
419
|
+
default:
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
default:
|
|
423
|
+
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
return protect([&] {
|
|
428
|
+
if (rb_obj_is_kind_of(x, rb_cTime)) {
|
|
429
|
+
return metaType == QMetaType::QDateTime;
|
|
430
|
+
}
|
|
431
|
+
static auto dateTimeClass = RubyClass::fromPath("DateTime");
|
|
432
|
+
if (rb_obj_is_kind_of(x, dateTimeClass)) {
|
|
433
|
+
return metaType == QMetaType::QDateTime;
|
|
434
|
+
}
|
|
435
|
+
static auto dateClass = RubyClass::fromPath("Date");
|
|
436
|
+
if (rb_obj_is_kind_of(x, dateClass)) {
|
|
437
|
+
return metaType == QMetaType::QDate || metaType == QMetaType::QDateTime;
|
|
438
|
+
}
|
|
439
|
+
static auto objectBaseClass = RubyClass::fromPath("QML::QtObjectBase");
|
|
440
|
+
if (rb_obj_is_kind_of(x, objectBaseClass)) {
|
|
441
|
+
if (metaType == QMetaType::QObjectStar) {
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
if (QMetaType::metaObjectForType(metaType)) {
|
|
445
|
+
auto metaObj = QMetaType::metaObjectForType(metaType);
|
|
446
|
+
if (x.to<QObject *>()->inherits(metaObj->className())) {
|
|
447
|
+
return true;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
if (rb_obj_is_kind_of(x, wrapperRubyClass<Ext::MetaObject>())) {
|
|
453
|
+
return metaType == QMetaType::type("const QMetaObject*");
|
|
454
|
+
}
|
|
455
|
+
auto accessModule = RubyModule::fromPath("QML::Access");
|
|
456
|
+
if (rb_obj_is_kind_of(x, accessModule)) {
|
|
457
|
+
return metaType == QMetaType::QObjectStar;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
static auto pointClass = RubyModule::fromPath("QML::Geometry::Point");
|
|
461
|
+
if (rb_obj_is_kind_of(x, pointClass)) {
|
|
462
|
+
return metaType == QMetaType::QPoint || metaType == QMetaType::QPointF;
|
|
463
|
+
}
|
|
464
|
+
static auto sizeClass = RubyModule::fromPath("QML::Geometry::Size");
|
|
465
|
+
if (rb_obj_is_kind_of(x, sizeClass)) {
|
|
466
|
+
return metaType == QMetaType::QSize || metaType == QMetaType::QSizeF;
|
|
467
|
+
}
|
|
468
|
+
static auto rectClass = RubyModule::fromPath("QML::Geometry::Rectangle");
|
|
469
|
+
if (rb_obj_is_kind_of(x, rectClass)) {
|
|
470
|
+
return metaType == QMetaType::QRect || metaType == QMetaType::QRectF;
|
|
471
|
+
}
|
|
472
|
+
static auto listModelClass = RubyModule::fromPath("QML::Data::ListModel");
|
|
473
|
+
|
|
474
|
+
if (rb_obj_is_kind_of(x, listModelClass)) {
|
|
475
|
+
return metaType == QMetaType::QObjectStar;
|
|
476
|
+
}
|
|
477
|
+
return false;
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
int RubyValue::defaultMetaType() const
|
|
482
|
+
{
|
|
483
|
+
auto x = *this;
|
|
484
|
+
switch (rb_type(x)) {
|
|
485
|
+
case T_NIL:
|
|
486
|
+
return QMetaType::UnknownType;
|
|
487
|
+
case T_TRUE:
|
|
488
|
+
case T_FALSE:
|
|
489
|
+
return QMetaType::Bool;
|
|
490
|
+
case T_FIXNUM:
|
|
491
|
+
case T_BIGNUM:
|
|
492
|
+
return QMetaType::Int;
|
|
493
|
+
case T_FLOAT:
|
|
494
|
+
return QMetaType::Double;
|
|
495
|
+
case T_SYMBOL:
|
|
496
|
+
return QMetaType::QString;
|
|
497
|
+
case T_STRING:
|
|
498
|
+
if (rb_enc_get_index(x) == rb_ascii8bit_encindex()) {
|
|
499
|
+
return QMetaType::QByteArray;
|
|
500
|
+
} else {
|
|
501
|
+
return QMetaType::QString;
|
|
502
|
+
}
|
|
503
|
+
case T_ARRAY:
|
|
504
|
+
return QMetaType::QVariantList;
|
|
505
|
+
case T_HASH:
|
|
506
|
+
return QMetaType::QVariantHash;
|
|
507
|
+
default:
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
return protect([&]() -> int {
|
|
511
|
+
if (rb_obj_is_kind_of(x, rb_cTime)) {
|
|
512
|
+
return QMetaType::QDateTime;
|
|
513
|
+
}
|
|
514
|
+
static auto dateTimeClass = RubyModule::fromPath("DateTime");
|
|
515
|
+
if (rb_obj_is_kind_of(x, dateTimeClass)) {
|
|
516
|
+
return QMetaType::QDateTime;
|
|
517
|
+
}
|
|
518
|
+
static auto dateClass = RubyModule::fromPath("Date");
|
|
519
|
+
if (rb_obj_is_kind_of(x, dateClass)) {
|
|
520
|
+
return QMetaType::QDate;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
static auto objectBaseClass = RubyClass::fromPath("QML::QtObjectBase");
|
|
524
|
+
if (rb_obj_is_kind_of(x, objectBaseClass)) {
|
|
525
|
+
return QMetaType::QObjectStar;
|
|
526
|
+
}
|
|
527
|
+
if (rb_obj_is_kind_of(x, wrapperRubyClass<Ext::MetaObject>())) {
|
|
528
|
+
return QMetaType::type("const QMetaObject*");
|
|
529
|
+
}
|
|
530
|
+
auto accessModule = RubyModule::fromPath("QML::Access");
|
|
531
|
+
if (rb_obj_is_kind_of(x, accessModule)) {
|
|
532
|
+
return QMetaType::QObjectStar;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
static auto pointClass = RubyModule::fromPath("QML::Geometry::Point");
|
|
536
|
+
if (rb_obj_is_kind_of(x, pointClass)) {
|
|
537
|
+
return QMetaType::QPointF;
|
|
538
|
+
}
|
|
539
|
+
static auto sizeClass = RubyModule::fromPath("QML::Geometry::Size");
|
|
540
|
+
if (rb_obj_is_kind_of(x, sizeClass)) {
|
|
541
|
+
return QMetaType::QSizeF;
|
|
542
|
+
}
|
|
543
|
+
static auto rectClass = RubyModule::fromPath("QML::Geometry::Rectangle");
|
|
544
|
+
if (rb_obj_is_kind_of(x, rectClass)) {
|
|
545
|
+
return QMetaType::QRectF;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
static auto listModelClass = RubyModule::fromPath("QML::Data::ListModel");
|
|
549
|
+
if (rb_obj_is_kind_of(x, listModelClass)) {
|
|
550
|
+
return QMetaType::QObjectStar;
|
|
551
|
+
}
|
|
552
|
+
return QMetaType::UnknownType;
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
RubyValue RubyValue::fromVariant(const QVariant &variant)
|
|
557
|
+
{
|
|
558
|
+
auto &hash = detail::converterHash->toRubyHash;
|
|
559
|
+
auto type = variant.userType();
|
|
560
|
+
if (QMetaType::metaObjectForType(type)) {
|
|
561
|
+
type = QMetaType::QObjectStar;
|
|
562
|
+
}
|
|
563
|
+
if (enumeratorMetaTypes->contains(type)) {
|
|
564
|
+
auto intValue = *static_cast<const int *>(variant.data());
|
|
565
|
+
return from(intValue);
|
|
566
|
+
}
|
|
567
|
+
if (!hash.contains(type)) {
|
|
568
|
+
fail("QML::ConversionError",
|
|
569
|
+
QString("failed to convert QVariant value (%1)")
|
|
570
|
+
.arg(QMetaType::typeName(type)));
|
|
571
|
+
}
|
|
572
|
+
return hash[type](variant);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
QVariant RubyValue::toVariant() const
|
|
576
|
+
{
|
|
577
|
+
return toVariant(defaultMetaType());
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
QVariant RubyValue::toVariant(int type) const
|
|
581
|
+
{
|
|
582
|
+
auto x = *this;
|
|
583
|
+
auto &hash = detail::converterHash->fromRubyHash;
|
|
584
|
+
if (!hash.contains(type)) {
|
|
585
|
+
auto metaobj = QMetaType::metaObjectForType(type);
|
|
586
|
+
if (metaobj) {
|
|
587
|
+
auto qobj = hash[QMetaType::QObjectStar](x).value<QObject *>();
|
|
588
|
+
if (qobj->inherits(metaobj->className())) {
|
|
589
|
+
return QVariant::fromValue(qobj);
|
|
590
|
+
}
|
|
591
|
+
fail("QML::ConversionError",
|
|
592
|
+
QString("failed to convert QObject value (%1 to %2)")
|
|
593
|
+
.arg(qobj->metaObject()->className())
|
|
594
|
+
.arg(metaobj->className()));
|
|
595
|
+
}
|
|
596
|
+
if (enumeratorMetaTypes->contains(type)) {
|
|
597
|
+
auto intValue = to<int>();
|
|
598
|
+
auto data = QMetaType::create(type);
|
|
599
|
+
*static_cast<int *>(data) = intValue;
|
|
600
|
+
return QVariant(type, data);
|
|
601
|
+
}
|
|
602
|
+
fail("QML::ConversionError",
|
|
603
|
+
QString("failed to convert Ruby value (%1 to %2)")
|
|
604
|
+
.arg(rb_obj_classname(x))
|
|
605
|
+
.arg(QMetaType::typeName(type)));
|
|
606
|
+
return QVariant();
|
|
607
|
+
}
|
|
608
|
+
return hash[type](x);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
RubyValue RubyValue::fromQObject(QObject *obj, bool implicit)
|
|
612
|
+
{
|
|
613
|
+
if (!obj) {
|
|
614
|
+
return Qnil;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
if (implicit) {
|
|
618
|
+
auto accessObj = dynamic_cast<AccessWrapper *>(obj);
|
|
619
|
+
if (accessObj) {
|
|
620
|
+
return accessObj->wrappedValue();
|
|
621
|
+
}
|
|
622
|
+
auto listModel = dynamic_cast<ListModel *>(obj);
|
|
623
|
+
if (listModel) {
|
|
624
|
+
return listModel->rubyModel();
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
auto data = ObjectData::getOrCreate(obj);
|
|
629
|
+
if (data->rubyObject) {
|
|
630
|
+
return data->rubyObject;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
auto metaobj = Ext::MetaObject::fromMetaObject(obj->metaObject());
|
|
634
|
+
auto pointer = Ext::Pointer::fromQObject(obj, false);
|
|
635
|
+
|
|
636
|
+
RubyValue wrapper;
|
|
637
|
+
protect([&] {
|
|
638
|
+
auto klass = rb_funcall(metaobj, RUBYQML_INTERN("build_class"), 0);
|
|
639
|
+
wrapper = rb_obj_alloc(klass);
|
|
640
|
+
rb_funcall(wrapper, RUBYQML_INTERN("pointer="), 1, pointer);
|
|
641
|
+
rb_obj_call_init(wrapper, 0, nullptr);
|
|
642
|
+
});
|
|
643
|
+
data->rubyObject = wrapper;
|
|
644
|
+
return wrapper;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
QObject *RubyValue::toQObject() const
|
|
648
|
+
{
|
|
649
|
+
auto x = *this;
|
|
650
|
+
|
|
651
|
+
if (x == RubyValue()) {
|
|
652
|
+
return nullptr;
|
|
653
|
+
}
|
|
654
|
+
static auto accessModule = RubyModule::fromPath("QML::Access");
|
|
655
|
+
if (x.isKindOf(accessModule)) {
|
|
656
|
+
auto wrapperFactory = protect([&] {
|
|
657
|
+
return rb_funcall(rb_obj_class(x), RUBYQML_INTERN("access_wrapper_factory"), 0);
|
|
658
|
+
});
|
|
659
|
+
return wrapperRubyClass<Ext::AccessWrapperFactory>().unwrap(wrapperFactory)->create(x);
|
|
660
|
+
}
|
|
661
|
+
static auto listModelClass = RubyModule::fromPath("QML::Data::ListModel");
|
|
662
|
+
if (x.isKindOf(listModelClass)) {
|
|
663
|
+
return new ListModel(x);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
static auto objectBaseClass = RubyClass::fromPath("QML::QtObjectBase");
|
|
667
|
+
if (!x.isKindOf(objectBaseClass)) {
|
|
668
|
+
fail("QML::ConversionError",
|
|
669
|
+
QString("expected QML::QtObjectbase, got %1")
|
|
670
|
+
.arg(x.send("class").send("name").to<QString>()));
|
|
671
|
+
}
|
|
672
|
+
auto objptr = x.send(RUBYQML_INTERN("pointer"));
|
|
673
|
+
auto obj = wrapperRubyClass<Ext::Pointer>().unwrap(objptr)->fetchQObject();
|
|
674
|
+
Ext::MetaObject::fromMetaObject(obj->metaObject()).send(RUBYQML_INTERN("build_class"));
|
|
675
|
+
return obj;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
ID RubyValue::toID() const
|
|
679
|
+
{
|
|
680
|
+
return protect([&] {
|
|
681
|
+
return SYM2ID(rb_convert_type(*this, T_SYMBOL, "Symbol", "to_sym"));
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
void RubyValue::addEnumeratorMetaType(int metaType)
|
|
686
|
+
{
|
|
687
|
+
*enumeratorMetaTypes << metaType;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
} // namespace RubyQml
|