rui 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.
- data/.document +4 -0
- data/COPYING +165 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +24 -0
- data/README.md +8 -0
- data/Rakefile +43 -0
- data/VERSION +1 -0
- data/examples/autogui/main.rb +12 -0
- data/examples/hello/main.rb +13 -0
- data/examples/kderun.rb +4 -0
- data/examples/qtrun.rb +4 -0
- data/examples/signals/main.rb +15 -0
- data/lib/rui/descriptor.rb +241 -0
- data/lib/rui/factory.rb +84 -0
- data/lib/rui/observer_utils.rb +178 -0
- data/lib/rui/toolkits/kde/kde.rb +276 -0
- data/lib/rui/toolkits/qt/qt.rb +350 -0
- data/lib/rui/toolkits/qtbase/gui_builder.rb +344 -0
- data/lib/rui/toolkits/qtbase/qt.rb +555 -0
- data/lib/rui/utils.rb +42 -0
- data/lib/rui.rb +54 -0
- data/rui.gemspec +92 -0
- data/test/helper.rb +17 -0
- data/test/test_descriptor.rb +237 -0
- data/test/test_factory.rb +38 -0
- data/test/test_observer_utils.rb +67 -0
- metadata +189 -0
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
# Copyright (c) 2009-2010 Paolo Capriotti <p.capriotti@gmail.com>
|
|
2
|
+
#
|
|
3
|
+
# This library is free software; you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU Lesser General Public License as
|
|
5
|
+
# published by the Free Software Foundation; either version 3 of the
|
|
6
|
+
# License, or (at your option) any later version.
|
|
7
|
+
|
|
8
|
+
require 'rui/observer_utils'
|
|
9
|
+
require 'rui/descriptor'
|
|
10
|
+
require 'rui/toolkits/qtbase/gui_builder'
|
|
11
|
+
|
|
12
|
+
ParseException = Class.new(Exception)
|
|
13
|
+
|
|
14
|
+
class Qt::Variant
|
|
15
|
+
#
|
|
16
|
+
# Convert any marshallable ruby object into a QVariant.
|
|
17
|
+
#
|
|
18
|
+
def self.from_ruby(x)
|
|
19
|
+
new(Marshal.dump(x))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#
|
|
23
|
+
# Extract the ruby object contained in a QVariant.
|
|
24
|
+
#
|
|
25
|
+
def to_ruby
|
|
26
|
+
str = toString
|
|
27
|
+
Marshal.load(str) if str
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Qt::ByteArray
|
|
32
|
+
def self.from_hex(str)
|
|
33
|
+
new([str.gsub(/\W+/, '')].pack('H*'))
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class Qt::Painter
|
|
38
|
+
#
|
|
39
|
+
# Ensure this painter is closed after the block is executed.
|
|
40
|
+
#
|
|
41
|
+
def paint
|
|
42
|
+
yield self
|
|
43
|
+
ensure
|
|
44
|
+
self.end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
#
|
|
48
|
+
# Execute a block, then restore the painter state to what it
|
|
49
|
+
# was before execution.
|
|
50
|
+
#
|
|
51
|
+
def saving
|
|
52
|
+
save
|
|
53
|
+
yield self
|
|
54
|
+
ensure
|
|
55
|
+
restore
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class Qt::Image
|
|
60
|
+
#
|
|
61
|
+
# Convert this image to a pixmap.
|
|
62
|
+
#
|
|
63
|
+
def to_pix
|
|
64
|
+
Qt::Pixmap.from_image self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
#
|
|
68
|
+
# Paint on an image using the given block. The block is passed
|
|
69
|
+
# a painter to use for drawing.
|
|
70
|
+
#
|
|
71
|
+
def self.painted(size, &blk)
|
|
72
|
+
img = Qt::Image.new(size.x, size.y, Qt::Image::Format_ARGB32_Premultiplied)
|
|
73
|
+
img.fill(0)
|
|
74
|
+
Qt::Painter.new(img).paint(&blk)
|
|
75
|
+
img
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# Render an svg object onto a new image of the specified size. If id is not
|
|
80
|
+
# specified, the whole svg file is rendered.
|
|
81
|
+
#
|
|
82
|
+
def self.from_renderer(size, renderer, id = nil)
|
|
83
|
+
img = Qt::Image.painted(size) do |p|
|
|
84
|
+
if id
|
|
85
|
+
renderer.render(p, id)
|
|
86
|
+
else
|
|
87
|
+
renderer.render(p)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
img
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
module PrintablePoint
|
|
95
|
+
def ==(other)
|
|
96
|
+
self.x == other.x and self.y == other.y
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def to_s
|
|
100
|
+
"(#{self.x}, #{self.y})"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
module PrintableRect
|
|
105
|
+
def to_s
|
|
106
|
+
"[#{self.x}, #{self.y} - #{self.width}, #{self.height}]"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
class Qt::Point
|
|
111
|
+
include PrintablePoint
|
|
112
|
+
|
|
113
|
+
def to_f
|
|
114
|
+
Qt::PointF.new(self.x, self.y)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
class Qt::PointF
|
|
119
|
+
include PrintablePoint
|
|
120
|
+
|
|
121
|
+
def to_i
|
|
122
|
+
Qt::Point.new(self.x.to_i, self.y.to_i)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class Qt::Size
|
|
127
|
+
include PrintablePoint
|
|
128
|
+
|
|
129
|
+
def x
|
|
130
|
+
width
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def y
|
|
134
|
+
height
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
class Qt::SizeF
|
|
139
|
+
include PrintablePoint
|
|
140
|
+
|
|
141
|
+
def x
|
|
142
|
+
width
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def y
|
|
146
|
+
height
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
class Qt::Rect
|
|
151
|
+
include PrintableRect
|
|
152
|
+
|
|
153
|
+
def to_f
|
|
154
|
+
Qt::RectF.new(self.x, self.y, self.width, self.height)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
class Qt::RectF
|
|
159
|
+
include PrintableRect
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
class Qt::Pixmap
|
|
163
|
+
#
|
|
164
|
+
# Qt > 4.6 provides effects to be applied to Qt::GraphicsItem's.
|
|
165
|
+
# Since kaya effects work at a lower level of abstraction (i.e. at
|
|
166
|
+
# pixmap/image level), we embed effects directly in a pixmap.
|
|
167
|
+
#
|
|
168
|
+
# When a pixmap is assigned to a Qt::GraphicsItem, its effects are
|
|
169
|
+
# transferred to the item.
|
|
170
|
+
#
|
|
171
|
+
def effects
|
|
172
|
+
@effects ||= []
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
private :effects
|
|
176
|
+
|
|
177
|
+
#
|
|
178
|
+
# Add an effect to this pixmap. If later this pixmap is assigned to an
|
|
179
|
+
# Item, all its effects will be transferred to it.
|
|
180
|
+
#
|
|
181
|
+
def add_effect(effect)
|
|
182
|
+
effects << effect
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
#
|
|
186
|
+
# Render a pixmap from an svg file. See also Qt::Image#renderer.
|
|
187
|
+
#
|
|
188
|
+
def self.from_svg(size, file, id = nil)
|
|
189
|
+
from_renderer(size, Qt::SvgRenderer.new(file), id)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
#
|
|
193
|
+
# Render a pixmap using an svg renderer. See also Qt::Image#renderer.
|
|
194
|
+
#
|
|
195
|
+
def self.from_renderer(size, renderer, id = nil)
|
|
196
|
+
Qt::Image.from_renderer(size, renderer, id).to_pix
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def to_pix
|
|
200
|
+
self
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
class Qt::MetaObject
|
|
205
|
+
def create_signal_map
|
|
206
|
+
map = {}
|
|
207
|
+
(0...methodCount).map do |i|
|
|
208
|
+
m = method(i)
|
|
209
|
+
if m.methodType == Qt::MetaMethod::Signal
|
|
210
|
+
sign = m.signature
|
|
211
|
+
sign =~ /^(.*)\(.*\)$/
|
|
212
|
+
sig = $1.underscore.to_sym
|
|
213
|
+
val = [sign, m.parameterTypes]
|
|
214
|
+
map[sig] ||= []
|
|
215
|
+
map[sig] << val
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
map
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
class Qt::Base
|
|
223
|
+
include Observable
|
|
224
|
+
|
|
225
|
+
class SignalDisconnecter
|
|
226
|
+
def initialize(obj, sig)
|
|
227
|
+
@obj = obj
|
|
228
|
+
@sig = sig
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def disconnect!
|
|
232
|
+
@obj.disconnect(@sig)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
class ObserverDisconnecter
|
|
237
|
+
def initialize(obj, observer)
|
|
238
|
+
@obj = obj
|
|
239
|
+
@observer = observer
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def disconnect!
|
|
243
|
+
@obj.delete_observer(@observer)
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
class Signal
|
|
248
|
+
attr_reader :symbol
|
|
249
|
+
|
|
250
|
+
def initialize(signal, types)
|
|
251
|
+
raise "Only symbols are supported as signals" unless signal.is_a?(Symbol)
|
|
252
|
+
@symbol = signal
|
|
253
|
+
@types = types
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def self.create(signal, types)
|
|
257
|
+
if signal.is_a?(self)
|
|
258
|
+
signal
|
|
259
|
+
else
|
|
260
|
+
new(signal, types)
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def to_s
|
|
265
|
+
@symbol.to_s
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def on(sig, types = nil, &blk)
|
|
270
|
+
sig = Signal.create(sig, types)
|
|
271
|
+
candidates = if is_a? Qt::Object
|
|
272
|
+
signal_map[sig.symbol]
|
|
273
|
+
end
|
|
274
|
+
if candidates
|
|
275
|
+
if types
|
|
276
|
+
# find candidate with the correct argument types
|
|
277
|
+
candidates = candidates.find_all{|s| s[1] == types }
|
|
278
|
+
end
|
|
279
|
+
if candidates.size > 1
|
|
280
|
+
# find candidate with the correct arity
|
|
281
|
+
arity = blk.arity
|
|
282
|
+
if blk.arity == -1
|
|
283
|
+
# take first
|
|
284
|
+
candidates = [candidates.first]
|
|
285
|
+
else
|
|
286
|
+
candidates = candidates.find_all{|s| s[1].size == arity }
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
if candidates.size > 1
|
|
290
|
+
raise "Ambiguous overload for #{sig} with arity #{arity}"
|
|
291
|
+
elsif candidates.empty?
|
|
292
|
+
msg = if types
|
|
293
|
+
"with types #{types.join(' ')}"
|
|
294
|
+
else
|
|
295
|
+
"with arity #{blk.arity}"
|
|
296
|
+
end
|
|
297
|
+
raise "No overload for #{sig} #{msg}"
|
|
298
|
+
end
|
|
299
|
+
sign = SIGNAL(candidates.first[0])
|
|
300
|
+
connect(sign, &blk)
|
|
301
|
+
SignalDisconnecter.new(self, sign)
|
|
302
|
+
else
|
|
303
|
+
observer = observe(sig.symbol, &blk)
|
|
304
|
+
ObserverDisconnecter.new(self, observer)
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def in(interval, &blk)
|
|
309
|
+
Qt::Timer.in(interval, self, &blk)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def run_later(&blk)
|
|
313
|
+
self.in(0, &blk)
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def signal_map
|
|
317
|
+
self.class.signal_map(self)
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def self.signal_map(obj)
|
|
321
|
+
@signal_map ||= self.create_signal_map(obj)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def self.create_signal_map(obj)
|
|
325
|
+
obj.meta_object.create_signal_map
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def gui=(g)
|
|
329
|
+
setGUI(g)
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
class Qt::Timer
|
|
334
|
+
#
|
|
335
|
+
# Execute the given block every interval milliseconds and return a timer
|
|
336
|
+
# object. Note that if the timer is garbage collected, the block will not
|
|
337
|
+
# be executed anymore, so the caller should keep a reference to it for as
|
|
338
|
+
# long as needed.
|
|
339
|
+
# To prevent further invocations of the block, use QTimer#stop.
|
|
340
|
+
#
|
|
341
|
+
def self.every(interval, &blk)
|
|
342
|
+
time = Qt::Time.new
|
|
343
|
+
time.restart
|
|
344
|
+
|
|
345
|
+
timer = new
|
|
346
|
+
timer.connect(SIGNAL('timeout()')) { blk[time.elapsed] }
|
|
347
|
+
timer.start(interval)
|
|
348
|
+
# return the timer, so that the caller
|
|
349
|
+
# has a chance to keep it referenced, so
|
|
350
|
+
# that it is not garbage collected
|
|
351
|
+
timer
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
#
|
|
355
|
+
# Execute the given block after interval milliseconds. If target is
|
|
356
|
+
# specified, the block is invoked in the context of target.
|
|
357
|
+
#
|
|
358
|
+
def self.in(interval, target = nil, &blk)
|
|
359
|
+
single_shot(interval,
|
|
360
|
+
Qt::BlockInvocation.new(target, blk, 'invoke()'),
|
|
361
|
+
SLOT('invoke()'))
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
module ListLike
|
|
366
|
+
module ClassMethods
|
|
367
|
+
#
|
|
368
|
+
# Create a list from an array of pairs (text, data)
|
|
369
|
+
# The data for each item can be retrieved using the
|
|
370
|
+
# item's get method.
|
|
371
|
+
# Note that if an array element is not a pair, its
|
|
372
|
+
# value will be used both for the text and for the
|
|
373
|
+
# data.
|
|
374
|
+
#
|
|
375
|
+
# For example: <tt>list.current_item.get</tt>
|
|
376
|
+
#
|
|
377
|
+
def from_a(parent, array)
|
|
378
|
+
list = new(parent)
|
|
379
|
+
list.reset_from_a(array)
|
|
380
|
+
list
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
#
|
|
385
|
+
# Select the item for which the given block
|
|
386
|
+
# evaluates to true.
|
|
387
|
+
#
|
|
388
|
+
def select_item(&blk)
|
|
389
|
+
(0...count).each do |i|
|
|
390
|
+
if blk[item(i).get]
|
|
391
|
+
self.current_index = i
|
|
392
|
+
break i
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
nil
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
#
|
|
399
|
+
# Populate the list with values from an array.
|
|
400
|
+
# See also from_a.
|
|
401
|
+
#
|
|
402
|
+
def reset_from_a(array)
|
|
403
|
+
clear
|
|
404
|
+
array.each do |values|
|
|
405
|
+
text, data = if values.is_a?(String)
|
|
406
|
+
[values, values]
|
|
407
|
+
else
|
|
408
|
+
values
|
|
409
|
+
end
|
|
410
|
+
create_item(text, data)
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def self.included(base)
|
|
415
|
+
base.extend ClassMethods
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
class Qt::ListWidget
|
|
420
|
+
FROM_A_DATA_ROLE = Qt::UserRole
|
|
421
|
+
include ListLike
|
|
422
|
+
|
|
423
|
+
class Item < Qt::ListWidgetItem
|
|
424
|
+
def initialize(text, list, data)
|
|
425
|
+
super(text, list)
|
|
426
|
+
set_data(FROM_A_DATA_ROLE, Qt::Variant.from_ruby(data))
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def get
|
|
430
|
+
data(FROM_A_DATA_ROLE).to_ruby
|
|
431
|
+
end
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
def current_index=(i)
|
|
435
|
+
self.current_row = i
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def create_item(text, data)
|
|
439
|
+
Item.new(text, self, data)
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
class Qt::FileDialog
|
|
444
|
+
def self.get_open_url(dir, filter, parent, caption)
|
|
445
|
+
filename = get_open_file_name(parent, caption, dir.to_local_file, filter)
|
|
446
|
+
Qt::Url.from_local_file(filename)
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def self.get_save_url(dir, filter, parent, caption)
|
|
450
|
+
filename = get_save_file_name(parent, caption, dir.to_local_file, filter)
|
|
451
|
+
Qt::Url.from_local_file(filename)
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
class Qt::Url
|
|
456
|
+
def is_local_file
|
|
457
|
+
true
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
module ModelUtils
|
|
462
|
+
#
|
|
463
|
+
# Helper method to delete model rows from within a block. This method
|
|
464
|
+
# ensures that the appropriate begin/end functions are called.
|
|
465
|
+
#
|
|
466
|
+
def removing_rows(parent, first, last)
|
|
467
|
+
if first > last
|
|
468
|
+
yield
|
|
469
|
+
else
|
|
470
|
+
begin
|
|
471
|
+
begin_remove_rows(parent || Qt::ModelIndex.new, first, last)
|
|
472
|
+
yield
|
|
473
|
+
ensure
|
|
474
|
+
end_remove_rows
|
|
475
|
+
end
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
#
|
|
480
|
+
# Helper method to insert model rows from within a block. This method
|
|
481
|
+
# ensures that the appropriate begin/end functions are called.
|
|
482
|
+
#
|
|
483
|
+
def inserting_rows(parent, first, last)
|
|
484
|
+
if first > last
|
|
485
|
+
yield
|
|
486
|
+
else
|
|
487
|
+
begin
|
|
488
|
+
begin_insert_rows(parent || Qt::ModelIndex.new, first, last)
|
|
489
|
+
yield
|
|
490
|
+
ensure
|
|
491
|
+
end_insert_rows
|
|
492
|
+
end
|
|
493
|
+
end
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
module Layoutable
|
|
498
|
+
attr_writer :owner
|
|
499
|
+
attr_accessor :main_layout
|
|
500
|
+
|
|
501
|
+
def add_layout(layout)
|
|
502
|
+
self.layout = layout
|
|
503
|
+
owner.main_layout = layout
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
def add_widget(w)
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
def add_accessor(name, result)
|
|
510
|
+
owner.metaclass_eval do
|
|
511
|
+
define_method(name) { result }
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
515
|
+
def buddies
|
|
516
|
+
@buddies ||= { }
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
def owner
|
|
520
|
+
@owner || self
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
class Qt::Widget
|
|
525
|
+
include Layoutable
|
|
526
|
+
|
|
527
|
+
def setGUI(gui)
|
|
528
|
+
RUI::GuiBuilder.build(self, gui)
|
|
529
|
+
buddies.each do |label, buddy|
|
|
530
|
+
label.buddy = owner.__send__(buddy)
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
class KDE::ComboBox
|
|
536
|
+
include ListLike
|
|
537
|
+
|
|
538
|
+
Item = Struct.new(:get)
|
|
539
|
+
|
|
540
|
+
def create_item(text, data)
|
|
541
|
+
add_item(text, Qt::Variant.from_ruby(data))
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
def current_item
|
|
545
|
+
item(current_index)
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
def item(i)
|
|
549
|
+
Item.new(item_data(i).to_ruby)
|
|
550
|
+
end
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
def KDE.download_tempfile(url, parent)
|
|
554
|
+
url.to_local_file
|
|
555
|
+
end
|
data/lib/rui/utils.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Copyright (c) 2009-2010 Paolo Capriotti <p.capriotti@gmail.com>
|
|
2
|
+
#
|
|
3
|
+
# This library is free software; you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU Lesser General Public License as
|
|
5
|
+
# published by the Free Software Foundation; either version 3 of the
|
|
6
|
+
# License, or (at your option) any later version.
|
|
7
|
+
|
|
8
|
+
class Object
|
|
9
|
+
def metaclass
|
|
10
|
+
class << self
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def metaclass_eval(&blk)
|
|
16
|
+
metaclass.instance_eval(&blk)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class String
|
|
21
|
+
#
|
|
22
|
+
# Convert from camel case to underscore_separated.
|
|
23
|
+
#
|
|
24
|
+
# Examples:
|
|
25
|
+
# connectToServer => connect_to_server
|
|
26
|
+
# POP3ConnectionManager => pop3_connection_manager
|
|
27
|
+
#
|
|
28
|
+
def underscore
|
|
29
|
+
self.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
|
30
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
|
31
|
+
downcase
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
#
|
|
35
|
+
# Convert from underscore-separated to camel case.
|
|
36
|
+
#
|
|
37
|
+
# Example: connect_to_server => connectToServer
|
|
38
|
+
#
|
|
39
|
+
def camelize
|
|
40
|
+
gsub(/_(.)/) {|m| $1.upcase }
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/rui.rb
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright (c) 2009-2010 Paolo Capriotti <p.capriotti@gmail.com>
|
|
2
|
+
#
|
|
3
|
+
# This library is free software; you can redistribute it and/or modify
|
|
4
|
+
# it under the terms of the GNU Lesser General Public License as
|
|
5
|
+
# published by the Free Software Foundation; either version 3 of the
|
|
6
|
+
# License, or (at your option) any later version.
|
|
7
|
+
|
|
8
|
+
require 'rubygems' rescue nil
|
|
9
|
+
require 'rui/observer_utils'
|
|
10
|
+
require 'rui/utils'
|
|
11
|
+
require 'builder'
|
|
12
|
+
|
|
13
|
+
case ($toolkit || :kde)
|
|
14
|
+
when :qt
|
|
15
|
+
require 'Qt4'
|
|
16
|
+
KDE = Qt
|
|
17
|
+
RUI = Qt
|
|
18
|
+
require 'rui/toolkits/qt/qt'
|
|
19
|
+
when :kde
|
|
20
|
+
require 'korundum4'
|
|
21
|
+
require 'rui/toolkits/kde/kde'
|
|
22
|
+
module RUI
|
|
23
|
+
MainWindow = KDE::XmlGuiWindow
|
|
24
|
+
|
|
25
|
+
def self.const_missing(c)
|
|
26
|
+
if KDE.const_defined?(c)
|
|
27
|
+
KDE.const_get(c)
|
|
28
|
+
else
|
|
29
|
+
Qt.const_get(c)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
module RUI
|
|
36
|
+
#
|
|
37
|
+
# Create a GUI descriptor using the descriptor DSL.
|
|
38
|
+
#
|
|
39
|
+
# A GUI descriptor, as returned by this function, can be applied to a Widget
|
|
40
|
+
# by settings the widget's gui property to it. For example:
|
|
41
|
+
#
|
|
42
|
+
# widget.gui = RUI::autogui do
|
|
43
|
+
# button(:text => "Hello world")
|
|
44
|
+
# end
|
|
45
|
+
#
|
|
46
|
+
# See {Descriptor} for more details on the general descriptor DSL.
|
|
47
|
+
#
|
|
48
|
+
# See {RUI::GuiBuilder} for a list of supported descriptor tags for GUI
|
|
49
|
+
# descriptors.
|
|
50
|
+
#
|
|
51
|
+
def self.autogui(name = :gui, opts = { }, &blk)
|
|
52
|
+
Descriptor.build(:gui, opts.merge(:gui_name => name), &blk)
|
|
53
|
+
end
|
|
54
|
+
end
|