qt 0.1.9 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 50d48e8571c76d7413f893a6189b7670629bd3a80123a131bf9cc00ffe6d818e
4
- data.tar.gz: bcb0081e9ebabc04175f7f041fdf8442293d08191e5ee6e2b26164d32c730942
3
+ metadata.gz: c0e7757f47bb17be90f64d3bcdd28ba17e5e8099a505062a7e7c3dd71aaedf37
4
+ data.tar.gz: cbf55606a5a16e12cb4ef47b73756a1f3ef3b65c1e500583928a44a4d28b97c4
5
5
  SHA512:
6
- metadata.gz: 82bde56dd8d499bfc122923554109e6f7f92dfea399ed6fd2f821737c29cfb487b0025908409273aeb13df2ca9ed57a36eb524142a968c24a84eba43af4836b3
7
- data.tar.gz: 0444cabcb5c8ce71559758e92168f0f357de967edaaf15671f5f867f7e115dc48615e49de6d4d9a3fa55c7d098da46460b810ec0ac07ff625922c724daeac575
6
+ metadata.gz: 1e5e470938bc069179be121de52a5e2986479a7fa8dec030d743de246fef73812729bc57ea67d4958c076e42e8d23ef703c0931e51544f206352e3ba45a3c463
7
+ data.tar.gz: bc3d7083a9617ad49b2b139d0948bec69257ad5991be08525de8228e87aa3457bdd9d4d2745b399bf20f0266143428565e3fb5d88e039255687eb90b38c7efe9
@@ -60,6 +60,7 @@ runtime_hpp = File.expand_path('../../ext/qt_ruby_bridge/qt_ruby_runtime.hpp', _
60
60
  runtime_cpp_files = %w[
61
61
  runtime_events.cpp
62
62
  runtime_signals.cpp
63
+ runtime_value_types.cpp
63
64
  ].map { |name| File.expand_path("../../ext/qt_ruby_bridge/#{name}", __dir__) }
64
65
 
65
66
  unless File.exist?(generated_cpp)
@@ -1,6 +1,8 @@
1
1
  #pragma once
2
2
 
3
3
  #include <QApplication>
4
+ #include <QList>
5
+ #include <QVariant>
4
6
 
5
7
  namespace QtRubyRuntime {
6
8
  using EventCallback = int (*)(void*, int, const char*);
@@ -13,6 +15,10 @@ QApplication* qapplication_new(const char* argv0);
13
15
  // Returns false when teardown is rejected by runtime safety checks.
14
16
  bool qapplication_delete(void* app_handle);
15
17
 
18
+ // FFI-safe conversion for public Qt QList<int> API parameters and results.
19
+ QList<int> qint_list_from_variant(const QVariant& value);
20
+ QVariant qvariant_from_qint_list(const QList<int>& value);
21
+
16
22
  void set_event_callback(void* callback_ptr);
17
23
  void watch_qobject_event(void* object_handle, int event_type);
18
24
  void unwatch_qobject_event(void* object_handle, int event_type);
@@ -19,6 +19,7 @@ namespace QtRubyRuntime {
19
19
  constexpr int kEventCallbackIgnore = 0;
20
20
  constexpr int kEventCallbackContinue = 1;
21
21
  constexpr int kEventCallbackConsume = 2;
22
+ constexpr int kEventCallbackReject = 3;
22
23
 
23
24
  EventCallback& event_callback_ref() {
24
25
  static EventCallback callback = nullptr;
@@ -234,6 +235,10 @@ class EventFilter : public QObject {
234
235
  event->accept();
235
236
  return true;
236
237
  }
238
+ if (callback_result == kEventCallbackReject) {
239
+ event->ignore();
240
+ return true;
241
+ }
237
242
  return QObject::eventFilter(watched, event);
238
243
  }
239
244
  };
@@ -244,10 +249,10 @@ EventFilter* event_filter_instance() {
244
249
  }
245
250
 
246
251
  void ensure_event_filter_installed() {
247
- static bool installed = false;
248
- if (!installed && qApp) {
252
+ static QApplication* installed_on = nullptr;
253
+ if (qApp && installed_on != qApp) {
249
254
  qApp->installEventFilter(event_filter_instance());
250
- installed = true;
255
+ installed_on = qApp;
251
256
  }
252
257
  }
253
258
 
@@ -0,0 +1,22 @@
1
+ #include "qt_ruby_runtime.hpp"
2
+
3
+ namespace QtRubyRuntime {
4
+ QList<int> qint_list_from_variant(const QVariant& value) {
5
+ QList<int> result;
6
+ const QVariantList values = value.toList();
7
+ result.reserve(values.size());
8
+ for (const QVariant& entry : values) {
9
+ result.append(entry.toInt());
10
+ }
11
+ return result;
12
+ }
13
+
14
+ QVariant qvariant_from_qint_list(const QList<int>& value) {
15
+ QVariantList result;
16
+ result.reserve(value.size());
17
+ for (int entry : value) {
18
+ result.append(entry);
19
+ }
20
+ return result;
21
+ }
22
+ } // namespace QtRubyRuntime
@@ -7,6 +7,7 @@ module Qt
7
7
  EVENT_RESULT_IGNORE = 0
8
8
  EVENT_RESULT_CONTINUE = 1
9
9
  EVENT_RESULT_CONSUME = 2
10
+ EVENT_RESULT_REJECT = 3
10
11
 
11
12
  module_function
12
13
 
@@ -20,6 +21,7 @@ module Qt
20
21
  return EVENT_RESULT_CONTINUE unless handlers && !handlers.empty?
21
22
 
22
23
  results = handlers.map { |handler| handler.call(payload) }
24
+ return EVENT_RESULT_REJECT if results.include?(:reject)
23
25
  return EVENT_RESULT_CONSUME if results.any? { |result| result == true || result == :consume }
24
26
  return EVENT_RESULT_IGNORE if results.any? { |result| result == false || result == :ignore }
25
27
 
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Qt
4
+ # Owns copied Qt value objects returned through opaque FFI handles.
5
+ module ValueWrapper
6
+ module_function
7
+
8
+ def wrap(handle, qt_class, delete_method)
9
+ return nil if handle.nil? || handle.null?
10
+
11
+ wrapper = Qt.const_get(qt_class).allocate
12
+ wrapper.instance_variable_set(:@handle, handle)
13
+ ObjectSpace.define_finalizer(wrapper, finalizer(delete_method, handle))
14
+ wrapper
15
+ end
16
+
17
+ def finalizer(delete_method, handle)
18
+ proc do
19
+ Qt::Native.public_send(delete_method, handle) if Qt::Native.available?
20
+ rescue StandardError
21
+ nil
22
+ end
23
+ end
24
+ private_class_method :finalizer
25
+ end
26
+ end
data/lib/qt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Qt
4
- VERSION = '0.1.9'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/qt.rb CHANGED
@@ -24,6 +24,7 @@ require_relative 'qt/date_time_codec'
24
24
  require_relative 'qt/key_sequence_codec'
25
25
  require_relative 'qt/object_list_codec'
26
26
  require_relative 'qt/variant_codec'
27
+ require_relative 'qt/value_wrapper'
27
28
  require_relative 'qt/inspectable'
28
29
  require_relative 'qt/object_wrapper'
29
30
  require_relative 'qt/application_lifecycle'
@@ -38,7 +38,7 @@ def map_cpp_intlike_arg_type(type_name, qt_class, int_cast_types)
38
38
  map_qualified_intlike_arg_type(type_name, qt_class, int_cast_types)
39
39
  end
40
40
 
41
- def map_cpp_arg_type(type_name, qt_class: nil, int_cast_types: nil)
41
+ def map_cpp_arg_type(type_name, qt_class: nil, int_cast_types: nil, ast: nil)
42
42
  raw = type_name.to_s.strip
43
43
  return nil if raw.end_with?('&') && !raw.start_with?('const ')
44
44
 
@@ -46,7 +46,7 @@ def map_cpp_arg_type(type_name, qt_class: nil, int_cast_types: nil)
46
46
 
47
47
  type = raw
48
48
  type = type.sub(/\Aconst\s+/, '').sub(/\s*&\z/, '').strip
49
- return nil if unsupported_cpp_type?(type)
49
+ return { ffi: :string, cast: :qint_list_from_variant } if type == 'QList<int>'
50
50
  return { ffi: :string, cast: :qstring } if type == 'QString'
51
51
  return { ffi: :string, cast: :qdatetime_from_utf8 } if type == 'QDateTime'
52
52
  return { ffi: :string, cast: :qdate_from_utf8 } if type == 'QDate'
@@ -58,6 +58,12 @@ def map_cpp_arg_type(type_name, qt_class: nil, int_cast_types: nil)
58
58
  return { ffi: :string, cast: :qvariant_from_utf8 } if type == 'QVariant'
59
59
  return { ffi: :string } if compact_raw.match?(/\Aconst\s+char\s*\*\z/)
60
60
 
61
+ if ast_qt_value_class?(ast, type)
62
+ return { ffi: :pointer, cast: :qt_value_ref, value_class: type }
63
+ end
64
+
65
+ return nil if unsupported_cpp_type?(type)
66
+
61
67
  map_cpp_pointer_arg_type(type, qt_class) || map_cpp_intlike_arg_type(type, qt_class, int_cast_types)
62
68
  end
63
69
 
@@ -70,11 +76,25 @@ end
70
76
 
71
77
  def map_cpp_return_type(type_name, ast: nil)
72
78
  raw = type_name.to_s.strip
79
+ type = raw.sub(/\Aconst\s+/, '').sub(/\s*&\z/, '').strip
80
+ return { ffi_return: :string, return_cast: :qint_list_to_variant } if type == 'QList<int>'
73
81
  return nil if unsupported_cpp_type?(raw)
74
82
  return nil if raw.start_with?('const ') && raw.end_with?('*')
75
83
 
76
- type = raw.sub(/\Aconst\s+/, '').sub(/\s*&\z/, '').strip
77
- map_scalar_cpp_return_type(type) || map_pointer_cpp_return_type(type, ast: ast)
84
+ map_scalar_cpp_return_type(type) || map_pointer_cpp_return_type(type, ast: ast) || map_qt_value_return_type(type, ast: ast)
85
+ end
86
+
87
+ def ast_qt_value_class?(ast, type)
88
+ return false unless ast && type.match?(/\AQ[A-Z]\w*\z/)
89
+ return false unless ast_class_index(ast)[:methods_by_class].key?(type)
90
+
91
+ !class_inherits?(ast, type, 'QObject')
92
+ end
93
+
94
+ def map_qt_value_return_type(type, ast:)
95
+ return nil unless ast_qt_value_class?(ast, type)
96
+
97
+ { ffi_return: :pointer, return_cast: :qt_value_copy, value_class: type }
78
98
  end
79
99
 
80
100
  def map_scalar_cpp_return_type(type)
@@ -135,7 +155,7 @@ def parse_method_signature(method_decl)
135
155
  }
136
156
  end
137
157
 
138
- def build_auto_method_args(parsed, entry, qt_class, int_cast_types)
158
+ def build_auto_method_args(parsed, entry, qt_class, int_cast_types, ast)
139
159
  arg_cast_overrides = Array(entry[:arg_casts])
140
160
  params = parsed[:params]
141
161
  required_arg_count = 0
@@ -143,7 +163,7 @@ def build_auto_method_args(parsed, entry, qt_class, int_cast_types)
143
163
 
144
164
  params.each_with_index do |param, idx|
145
165
  cast_override = arg_cast_overrides[idx]
146
- arg_info = map_cpp_arg_type(param[:type], qt_class: qt_class, int_cast_types: int_cast_types)
166
+ arg_info = map_cpp_arg_type(param[:type], qt_class: qt_class, int_cast_types: int_cast_types, ast: ast)
147
167
  arg_info ||= { ffi: :int } if cast_override
148
168
  unless arg_info
149
169
  return nil unless skip_unsupported_optional_tail?(params, idx, param)
@@ -151,7 +171,12 @@ def build_auto_method_args(parsed, entry, qt_class, int_cast_types)
151
171
  break
152
172
  end
153
173
 
154
- args << { name: param[:name], ffi: arg_info[:ffi], cast: cast_override || arg_info[:cast] }.compact
174
+ args << {
175
+ name: param[:name],
176
+ ffi: arg_info[:ffi],
177
+ cast: cast_override || arg_info[:cast],
178
+ value_class: arg_info[:value_class]
179
+ }.compact
155
180
  required_arg_count += 1 unless param[:has_default]
156
181
  end
157
182
 
@@ -174,6 +199,7 @@ def build_auto_method_hash(entry, ret_info, args, required_arg_count)
174
199
  }
175
200
  method[:return_cast] = ret_info[:return_cast] if ret_info[:return_cast]
176
201
  method[:pointer_class] = ret_info[:pointer_class] if ret_info[:pointer_class]
202
+ method[:value_class] = ret_info[:value_class] if ret_info[:value_class]
177
203
  method
178
204
  end
179
205
 
@@ -184,7 +210,7 @@ def build_auto_method_from_decl(method_decl, entry, qt_class:, int_cast_types:,
184
210
  ret_info = map_cpp_return_type(parsed[:return_type], ast: ast)
185
211
  return nil unless ret_info
186
212
 
187
- args, required_arg_count = build_auto_method_args(parsed, entry, qt_class, int_cast_types)
213
+ args, required_arg_count = build_auto_method_args(parsed, entry, qt_class, int_cast_types, ast)
188
214
  return nil unless args
189
215
 
190
216
  build_auto_method_hash(entry, ret_info, args, required_arg_count)
@@ -352,7 +378,11 @@ def resolve_auto_method(ast, qt_class, auto_entry)
352
378
  built = resolve_auto_method_built_candidates(ast, qt_class, entry)
353
379
  return per_ast_cache[cache_key] = nil unless built
354
380
 
355
- per_ast_cache[cache_key] = built.min_by { |candidate| candidate[:method][:args].length }[:method]
381
+ per_ast_cache[cache_key] = built.min_by do |candidate|
382
+ method = candidate[:method]
383
+ value_arg_count = method[:args].count { |arg| arg[:cast] == :qt_value_ref }
384
+ [value_arg_count, method[:args].length]
385
+ end[:method]
356
386
  end
357
387
 
358
388
  def auto_entries_for_spec(spec, ast)
@@ -10,6 +10,8 @@ class CppMethodReturnEmitter
10
10
 
11
11
  def emit
12
12
  return emit_void if method[:ffi_return] == :void
13
+ return emit_qt_value_copy if method[:return_cast] == :qt_value_copy
14
+ return emit_qint_list if method[:return_cast] == :qint_list_to_variant
13
15
  return emit_qstring if qstring_return?
14
16
  return emit_qobject_list if qobject_list_return?
15
17
  return emit_qdatetime if qdatetime_return?
@@ -54,52 +56,86 @@ class CppMethodReturnEmitter
54
56
  end
55
57
 
56
58
  def emit_qstring
57
- lines << " const QString value = #{invocation};"
58
- lines << ' thread_local QByteArray utf8;'
59
- lines << ' utf8 = value.toUtf8();'
60
- lines << ' return utf8.constData();'
59
+ result = unique_local_name('result')
60
+ utf8 = unique_local_name('utf8')
61
+ lines << " const QString #{result} = #{invocation};"
62
+ lines << " thread_local QByteArray #{utf8};"
63
+ lines << " #{utf8} = #{result}.toUtf8();"
64
+ lines << " return #{utf8}.constData();"
61
65
  end
62
66
 
63
67
  def emit_qvariant
64
- lines << " const QVariant value = #{invocation};"
65
- lines << ' thread_local QByteArray utf8;'
66
- lines << ' utf8 = qvariant_to_bridge_string(value).toUtf8();'
67
- lines << ' return utf8.constData();'
68
+ result = unique_local_name('result')
69
+ utf8 = unique_local_name('utf8')
70
+ lines << " const QVariant #{result} = #{invocation};"
71
+ lines << " thread_local QByteArray #{utf8};"
72
+ lines << " #{utf8} = qvariant_to_bridge_string(#{result}).toUtf8();"
73
+ lines << " return #{utf8}.constData();"
68
74
  end
69
75
 
70
76
  def emit_qobject_list
71
- lines << " const QObjectList value = #{invocation};"
72
- lines << ' thread_local QByteArray utf8;'
73
- lines << ' utf8 = qobject_list_to_bridge_string(value).toUtf8();'
74
- lines << ' return utf8.constData();'
77
+ result = unique_local_name('result')
78
+ utf8 = unique_local_name('utf8')
79
+ lines << " const QObjectList #{result} = #{invocation};"
80
+ lines << " thread_local QByteArray #{utf8};"
81
+ lines << " #{utf8} = qobject_list_to_bridge_string(#{result}).toUtf8();"
82
+ lines << " return #{utf8}.constData();"
75
83
  end
76
84
 
77
85
  def emit_qdatetime
78
- lines << " const QDateTime value = #{invocation};"
79
- lines << ' thread_local QByteArray utf8;'
80
- lines << ' utf8 = qdatetime_to_bridge_string(value).toUtf8();'
81
- lines << ' return utf8.constData();'
86
+ result = unique_local_name('result')
87
+ utf8 = unique_local_name('utf8')
88
+ lines << " const QDateTime #{result} = #{invocation};"
89
+ lines << " thread_local QByteArray #{utf8};"
90
+ lines << " #{utf8} = qdatetime_to_bridge_string(#{result}).toUtf8();"
91
+ lines << " return #{utf8}.constData();"
82
92
  end
83
93
 
84
94
  def emit_qdate
85
- lines << " const QDate value = #{invocation};"
86
- lines << ' thread_local QByteArray utf8;'
87
- lines << ' utf8 = qdate_to_bridge_string(value).toUtf8();'
88
- lines << ' return utf8.constData();'
95
+ result = unique_local_name('result')
96
+ utf8 = unique_local_name('utf8')
97
+ lines << " const QDate #{result} = #{invocation};"
98
+ lines << " thread_local QByteArray #{utf8};"
99
+ lines << " #{utf8} = qdate_to_bridge_string(#{result}).toUtf8();"
100
+ lines << " return #{utf8}.constData();"
89
101
  end
90
102
 
91
103
  def emit_qtime
92
- lines << " const QTime value = #{invocation};"
93
- lines << ' thread_local QByteArray utf8;'
94
- lines << ' utf8 = qtime_to_bridge_string(value).toUtf8();'
95
- lines << ' return utf8.constData();'
104
+ result = unique_local_name('result')
105
+ utf8 = unique_local_name('utf8')
106
+ lines << " const QTime #{result} = #{invocation};"
107
+ lines << " thread_local QByteArray #{utf8};"
108
+ lines << " #{utf8} = qtime_to_bridge_string(#{result}).toUtf8();"
109
+ lines << " return #{utf8}.constData();"
96
110
  end
97
111
 
98
112
  def emit_pointer
99
113
  lines << " return const_cast<void*>(static_cast<const void*>(#{invocation}));"
100
114
  end
101
115
 
116
+ def emit_qt_value_copy
117
+ lines << " return new #{method[:value_class]}(#{invocation});"
118
+ end
119
+
120
+ def emit_qint_list
121
+ result = unique_local_name('result')
122
+ variant = unique_local_name('variant')
123
+ utf8 = unique_local_name('utf8')
124
+ lines << " const QList<int> #{result} = #{invocation};"
125
+ lines << " const QVariant #{variant} = QtRubyRuntime::qvariant_from_qint_list(#{result});"
126
+ lines << " thread_local QByteArray #{utf8};"
127
+ lines << " #{utf8} = qvariant_to_bridge_string(#{variant}).toUtf8();"
128
+ lines << " return #{utf8}.constData();"
129
+ end
130
+
102
131
  def emit_value
103
132
  lines << " return #{invocation};"
104
133
  end
134
+
135
+ def unique_local_name(suffix)
136
+ used = Array(method[:args]).map { |arg| arg[:name].to_s }.to_set
137
+ candidate = "qt_ruby_#{suffix}"
138
+ candidate += '_' while used.include?(candidate)
139
+ candidate
140
+ end
105
141
  end
@@ -15,9 +15,25 @@ def all_ffi_functions(specs, free_function_specs:)
15
15
  append_method_ffi_functions(fns, spec)
16
16
  end
17
17
 
18
+ value_wrapper_classes(specs, free_function_specs: free_function_specs).each do |qt_class|
19
+ fns << { name: qt_value_delete_function_name(qt_class), ffi_return: :void, args: [:pointer] }
20
+ end
21
+
18
22
  fns
19
23
  end
20
24
 
25
+ def value_wrapper_classes(specs, free_function_specs: [])
26
+ spec_classes = specs.flat_map do |spec|
27
+ spec[:methods].filter_map { |method| method[:value_class] if method[:return_cast] == :qt_value_copy }
28
+ end
29
+ free_classes = free_function_specs.filter_map { |spec| spec[:value_class] }
30
+ (spec_classes + free_classes).uniq.sort
31
+ end
32
+
33
+ def qt_value_delete_function_name(qt_class)
34
+ "qt_ruby_#{to_snake(qt_class)}_value_delete"
35
+ end
36
+
21
37
  def append_constructor_ffi_function(fns, spec)
22
38
  return if spec[:constructor][:mode] == :wrap_only
23
39
 
@@ -215,6 +215,8 @@ def build_qapplication_static_free_function_spec(ast, qt_name, int_cast_types)
215
215
  cpp_body =
216
216
  if candidate[:ffi_return] == :void
217
217
  ["QApplication::#{qt_name}();"]
218
+ elsif candidate[:return_cast] == :qt_value_copy
219
+ ["return new #{candidate[:value_class]}(QApplication::#{qt_name}());"]
218
220
  elsif candidate[:enum_cast]
219
221
  ["return static_cast<int>(QApplication::#{qt_name}());"]
220
222
  elsif candidate[:ffi_return] == :string
@@ -231,6 +233,7 @@ def build_qapplication_static_free_function_spec(ast, qt_name, int_cast_types)
231
233
  {
232
234
  name: "qt_ruby_#{native_name}",
233
235
  ffi_return: candidate[:ffi_return],
236
+ value_class: candidate[:value_class],
234
237
  args: [],
235
238
  cpp_return: ffi_return_to_cpp(candidate[:ffi_return]),
236
239
  cpp_args: '',
@@ -240,7 +243,8 @@ def build_qapplication_static_free_function_spec(ast, qt_name, int_cast_types)
240
243
  native: native_name,
241
244
  args: [],
242
245
  return_cast: candidate[:return_cast],
243
- pointer_class: candidate[:pointer_class]
246
+ pointer_class: candidate[:pointer_class],
247
+ value_class: candidate[:value_class]
244
248
  }
245
249
  }
246
250
  end
@@ -271,6 +275,7 @@ def qapplication_static_return_info(return_type, int_cast_types, ast:)
271
275
  ffi_return: mapped[:ffi_return],
272
276
  return_cast: mapped[:return_cast],
273
277
  pointer_class: mapped[:pointer_class],
278
+ value_class: mapped[:value_class],
274
279
  enum_cast: false
275
280
  }
276
281
  end
@@ -300,7 +300,8 @@ def discover_target_qt_classes(ast, scope)
300
300
  discover_related_value_classes(ast, base_targets, all_classes, template_classes).sort
301
301
  end
302
302
  wrapper_targets = timed("discover_target_qt_classes/#{scope}/related_qobject_wrappers") do
303
- discover_related_qobject_wrapper_classes(ast, targets, all_classes, template_classes, scope).sort
303
+ seed_classes = (targets + ['QApplication']).uniq
304
+ discover_related_qobject_wrapper_classes(ast, seed_classes, all_classes, template_classes, scope).sort
304
305
  end
305
306
  targets = (targets + wrapper_targets).uniq.sort
306
307
  debug_log(
@@ -250,7 +250,9 @@ def arg_expr(arg)
250
250
  when :qicon_ref then "*static_cast<QIcon*>(#{arg[:name]})"
251
251
  when :qany_string_view then "QAnyStringView(as_qstring(#{arg[:name]}))"
252
252
  when :qvariant_from_utf8 then "qvariant_from_bridge_value(#{arg[:name]})"
253
+ when :qint_list_from_variant then "QtRubyRuntime::qint_list_from_variant(qvariant_from_bridge_value(#{arg[:name]}))"
253
254
  when :alignment then "static_cast<Qt::Alignment>(#{arg[:name]})"
255
+ when :qt_value_ref then "*static_cast<#{arg[:value_class]}*>(#{arg[:name]})"
254
256
  when String then "static_cast<#{arg[:cast]}>(#{arg[:name]})"
255
257
  else
256
258
  arg[:name]
@@ -335,6 +337,15 @@ def generate_cpp_delete(lines)
335
337
  lines << '}'
336
338
  end
337
339
 
340
+ def generate_cpp_qt_value_deletes(lines, specs, free_function_specs)
341
+ value_wrapper_classes(specs, free_function_specs: free_function_specs).each do |qt_class|
342
+ lines << "extern \"C\" void #{qt_value_delete_function_name(qt_class)}(void* handle) {"
343
+ lines << " delete static_cast<#{qt_class}*>(handle);"
344
+ lines << '}'
345
+ lines << ''
346
+ end
347
+ end
348
+
338
349
  def cpp_method_signature(method)
339
350
  ['void* handle'] + method[:args].map { |arg| "#{ffi_to_cpp_type(arg[:ffi])} #{arg[:name]}" }
340
351
  end
@@ -381,6 +392,7 @@ def generate_cpp_bridge(specs, free_function_specs)
381
392
 
382
393
  specs.each { |spec| append_cpp_spec_methods(lines, spec) }
383
394
 
395
+ generate_cpp_qt_value_deletes(lines, specs, free_function_specs)
384
396
  generate_cpp_delete(lines)
385
397
  "#{lines.join("\n")}\n"
386
398
  end
@@ -640,6 +652,7 @@ def optional_arg_replacement(arg, safe)
640
652
  when :bool then "(#{safe}.nil? ? false : #{safe})"
641
653
  when :pointer then safe
642
654
  when :string
655
+ return "(#{safe}.nil? ? Qt::VariantCodec.encode([]) : Qt::VariantCodec.encode(#{safe}))" if arg[:cast] == :qint_list_from_variant
643
656
  return "(#{safe}.nil? ? '' : Qt::VariantCodec.encode(#{safe}))" if arg[:cast] == :qvariant_from_utf8
644
657
  return "(#{safe}.nil? ? '' : Qt::DateTimeCodec.encode_qdatetime(#{safe}))" if arg[:cast] == :qdatetime_from_utf8
645
658
  return "(#{safe}.nil? ? '' : Qt::DateTimeCodec.encode_qdate(#{safe}))" if arg[:cast] == :qdate_from_utf8
@@ -653,8 +666,13 @@ def optional_arg_replacement(arg, safe)
653
666
  end
654
667
 
655
668
  def ruby_arg_call_value(arg, safe, optional:)
669
+ if arg[:cast] == :qt_value_ref
670
+ return optional ? "(#{safe}.nil? ? nil : #{safe}.handle)" : "#{safe}.handle"
671
+ end
672
+
656
673
  return "Qt::StringCodec.to_qt_text(#{safe})" if text_bridge_arg?(arg) && !optional
657
674
  return "Qt::VariantCodec.encode(#{safe})" if arg[:cast] == :qvariant_from_utf8 && !optional
675
+ return "Qt::VariantCodec.encode(#{safe})" if arg[:cast] == :qint_list_from_variant && !optional
658
676
  return "Qt::DateTimeCodec.encode_qdatetime(#{safe})" if arg[:cast] == :qdatetime_from_utf8 && !optional
659
677
  return "Qt::DateTimeCodec.encode_qdate(#{safe})" if arg[:cast] == :qdate_from_utf8 && !optional
660
678
  return "Qt::DateTimeCodec.encode_qtime(#{safe})" if arg[:cast] == :qtime_from_utf8 && !optional
@@ -698,9 +716,14 @@ def ruby_native_method_body(method, rewritten_native_call)
698
716
  return "Qt::ObjectListCodec.decode(#{rewritten_native_call}, '#{method[:object_list_class]}')"
699
717
  end
700
718
  return "Qt::VariantCodec.decode(#{rewritten_native_call})" if method[:return_cast] == :qvariant_to_utf8
719
+ return "Qt::VariantCodec.decode(#{rewritten_native_call})" if method[:return_cast] == :qint_list_to_variant
701
720
  return "Qt::DateTimeCodec.decode_qdatetime(#{rewritten_native_call})" if method[:return_cast] == :qdatetime_to_utf8
702
721
  return "Qt::DateTimeCodec.decode_qdate(#{rewritten_native_call})" if method[:return_cast] == :qdate_to_utf8
703
722
  return "Qt::DateTimeCodec.decode_qtime(#{rewritten_native_call})" if method[:return_cast] == :qtime_to_utf8
723
+ if method[:return_cast] == :qt_value_copy
724
+ delete_method = qt_value_delete_function_name(method[:value_class])
725
+ return "Qt::ValueWrapper.wrap(#{rewritten_native_call}, '#{method[:value_class]}', :#{delete_method})"
726
+ end
704
727
  return "Qt::ObjectWrapper.wrap(#{rewritten_native_call}, '#{method[:pointer_class]}')" if method[:pointer_class]
705
728
 
706
729
  rewritten_native_call
@@ -899,6 +922,11 @@ def qapplication_class_method_body(method, native_call)
899
922
  return " Qt::DateTimeCodec.decode_qdatetime(#{native_call})" if method[:return_cast] == :qdatetime_to_utf8
900
923
  return " Qt::DateTimeCodec.decode_qdate(#{native_call})" if method[:return_cast] == :qdate_to_utf8
901
924
  return " Qt::DateTimeCodec.decode_qtime(#{native_call})" if method[:return_cast] == :qtime_to_utf8
925
+ return " Qt::VariantCodec.decode(#{native_call})" if method[:return_cast] == :qint_list_to_variant
926
+ if method[:return_cast] == :qt_value_copy
927
+ delete_method = qt_value_delete_function_name(method[:value_class])
928
+ return " Qt::ValueWrapper.wrap(#{native_call}, '#{method[:value_class]}', :#{delete_method})"
929
+ end
902
930
  return " Qt::ObjectWrapper.wrap(#{native_call}, '#{method[:pointer_class]}')" if method[:pointer_class]
903
931
 
904
932
  " #{native_call}"
@@ -1173,6 +1201,7 @@ def collect_qt_scoped_enum_constants(ast, warnings = [])
1173
1201
  next unless owner.match?(/\AQ[A-Z]\w*\z/)
1174
1202
  next if owner == 'Qt' || owner == 'QEvent'
1175
1203
 
1204
+ next_value = 0
1176
1205
  Array(node['inner']).each do |entry|
1177
1206
  next unless entry['kind'] == 'EnumConstantDecl'
1178
1207
 
@@ -1181,7 +1210,13 @@ def collect_qt_scoped_enum_constants(ast, warnings = [])
1181
1210
 
1182
1211
  raw_value = ast_extract_first_value(entry)
1183
1212
  value = parse_ast_integer_value(raw_value)
1184
- next if value.nil?
1213
+ value = next_value if value.nil? && !next_value.nil?
1214
+ if value.nil?
1215
+ next_value = nil
1216
+ next
1217
+ end
1218
+
1219
+ next_value = value + 1
1185
1220
 
1186
1221
  append_constant_with_conflict_warning(
1187
1222
  constants_by_owner[owner],
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maksim Veynberg
@@ -47,6 +47,7 @@ files:
47
47
  - ext/qt_ruby_bridge/qt_ruby_runtime.hpp
48
48
  - ext/qt_ruby_bridge/runtime_events.cpp
49
49
  - ext/qt_ruby_bridge/runtime_signals.cpp
50
+ - ext/qt_ruby_bridge/runtime_value_types.cpp
50
51
  - lib/qt.rb
51
52
  - lib/qt/application_lifecycle.rb
52
53
  - lib/qt/bridge.rb
@@ -66,6 +67,7 @@ files:
66
67
  - lib/qt/object_wrapper.rb
67
68
  - lib/qt/shortcut_compat.rb
68
69
  - lib/qt/string_codec.rb
70
+ - lib/qt/value_wrapper.rb
69
71
  - lib/qt/variant_codec.rb
70
72
  - lib/qt/version.rb
71
73
  - scripts/generate_bridge.rb