rui 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,4 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
data/COPYING ADDED
@@ -0,0 +1,165 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+
9
+ This version of the GNU Lesser General Public License incorporates
10
+ the terms and conditions of version 3 of the GNU General Public
11
+ License, supplemented by the additional permissions listed below.
12
+
13
+ 0. Additional Definitions.
14
+
15
+ As used herein, "this License" refers to version 3 of the GNU Lesser
16
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
17
+ General Public License.
18
+
19
+ "The Library" refers to a covered work governed by this License,
20
+ other than an Application or a Combined Work as defined below.
21
+
22
+ An "Application" is any work that makes use of an interface provided
23
+ by the Library, but which is not otherwise based on the Library.
24
+ Defining a subclass of a class defined by the Library is deemed a mode
25
+ of using an interface provided by the Library.
26
+
27
+ A "Combined Work" is a work produced by combining or linking an
28
+ Application with the Library. The particular version of the Library
29
+ with which the Combined Work was made is also called the "Linked
30
+ Version".
31
+
32
+ The "Minimal Corresponding Source" for a Combined Work means the
33
+ Corresponding Source for the Combined Work, excluding any source code
34
+ for portions of the Combined Work that, considered in isolation, are
35
+ based on the Application, and not on the Linked Version.
36
+
37
+ The "Corresponding Application Code" for a Combined Work means the
38
+ object code and/or source code for the Application, including any data
39
+ and utility programs needed for reproducing the Combined Work from the
40
+ Application, but excluding the System Libraries of the Combined Work.
41
+
42
+ 1. Exception to Section 3 of the GNU GPL.
43
+
44
+ You may convey a covered work under sections 3 and 4 of this License
45
+ without being bound by section 3 of the GNU GPL.
46
+
47
+ 2. Conveying Modified Versions.
48
+
49
+ If you modify a copy of the Library, and, in your modifications, a
50
+ facility refers to a function or data to be supplied by an Application
51
+ that uses the facility (other than as an argument passed when the
52
+ facility is invoked), then you may convey a copy of the modified
53
+ version:
54
+
55
+ a) under this License, provided that you make a good faith effort to
56
+ ensure that, in the event an Application does not supply the
57
+ function or data, the facility still operates, and performs
58
+ whatever part of its purpose remains meaningful, or
59
+
60
+ b) under the GNU GPL, with none of the additional permissions of
61
+ this License applicable to that copy.
62
+
63
+ 3. Object Code Incorporating Material from Library Header Files.
64
+
65
+ The object code form of an Application may incorporate material from
66
+ a header file that is part of the Library. You may convey such object
67
+ code under terms of your choice, provided that, if the incorporated
68
+ material is not limited to numerical parameters, data structure
69
+ layouts and accessors, or small macros, inline functions and templates
70
+ (ten or fewer lines in length), you do both of the following:
71
+
72
+ a) Give prominent notice with each copy of the object code that the
73
+ Library is used in it and that the Library and its use are
74
+ covered by this License.
75
+
76
+ b) Accompany the object code with a copy of the GNU GPL and this license
77
+ document.
78
+
79
+ 4. Combined Works.
80
+
81
+ You may convey a Combined Work under terms of your choice that,
82
+ taken together, effectively do not restrict modification of the
83
+ portions of the Library contained in the Combined Work and reverse
84
+ engineering for debugging such modifications, if you also do each of
85
+ the following:
86
+
87
+ a) Give prominent notice with each copy of the Combined Work that
88
+ the Library is used in it and that the Library and its use are
89
+ covered by this License.
90
+
91
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
92
+ document.
93
+
94
+ c) For a Combined Work that displays copyright notices during
95
+ execution, include the copyright notice for the Library among
96
+ these notices, as well as a reference directing the user to the
97
+ copies of the GNU GPL and this license document.
98
+
99
+ d) Do one of the following:
100
+
101
+ 0) Convey the Minimal Corresponding Source under the terms of this
102
+ License, and the Corresponding Application Code in a form
103
+ suitable for, and under terms that permit, the user to
104
+ recombine or relink the Application with a modified version of
105
+ the Linked Version to produce a modified Combined Work, in the
106
+ manner specified by section 6 of the GNU GPL for conveying
107
+ Corresponding Source.
108
+
109
+ 1) Use a suitable shared library mechanism for linking with the
110
+ Library. A suitable mechanism is one that (a) uses at run time
111
+ a copy of the Library already present on the user's computer
112
+ system, and (b) will operate properly with a modified version
113
+ of the Library that is interface-compatible with the Linked
114
+ Version.
115
+
116
+ e) Provide Installation Information, but only if you would otherwise
117
+ be required to provide such information under section 6 of the
118
+ GNU GPL, and only to the extent that such information is
119
+ necessary to install and execute a modified version of the
120
+ Combined Work produced by recombining or relinking the
121
+ Application with a modified version of the Linked Version. (If
122
+ you use option 4d0, the Installation Information must accompany
123
+ the Minimal Corresponding Source and Corresponding Application
124
+ Code. If you use option 4d1, you must provide the Installation
125
+ Information in the manner specified by section 6 of the GNU GPL
126
+ for conveying Corresponding Source.)
127
+
128
+ 5. Combined Libraries.
129
+
130
+ You may place library facilities that are a work based on the
131
+ Library side by side in a single library together with other library
132
+ facilities that are not Applications and are not covered by this
133
+ License, and convey such a combined library under terms of your
134
+ choice, if you do both of the following:
135
+
136
+ a) Accompany the combined library with a copy of the same work based
137
+ on the Library, uncombined with any other library facilities,
138
+ conveyed under the terms of this License.
139
+
140
+ b) Give prominent notice with the combined library that part of it
141
+ is a work based on the Library, and explaining where to find the
142
+ accompanying uncombined form of the same work.
143
+
144
+ 6. Revised Versions of the GNU Lesser General Public License.
145
+
146
+ The Free Software Foundation may publish revised and/or new versions
147
+ of the GNU Lesser General Public License from time to time. Such new
148
+ versions will be similar in spirit to the present version, but may
149
+ differ in detail to address new problems or concerns.
150
+
151
+ Each version is given a distinguishing version number. If the
152
+ Library as you received it specifies that a certain numbered version
153
+ of the GNU Lesser General Public License "or any later version"
154
+ applies to it, you have the option of following the terms and
155
+ conditions either of that published version or of any later version
156
+ published by the Free Software Foundation. If the Library as you
157
+ received it does not specify a version number of the GNU Lesser
158
+ General Public License, you may choose any version of the GNU Lesser
159
+ General Public License ever published by the Free Software Foundation.
160
+
161
+ If the Library as you received it specifies that a proxy can decide
162
+ whether future versions of the GNU Lesser General Public License shall
163
+ apply, that proxy's public statement of acceptance of any version is
164
+ permanent authorization for you to choose that version for the
165
+ Library.
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+ gem "builder"
6
+
7
+ # Add dependencies to develop your gem here.
8
+ # Include everything needed to run rake, tests, features, etc.
9
+ group :development do
10
+ gem "yard", "~> 0.6.0"
11
+ gem "bluecloth"
12
+ gem "bundler", "~> 1.0.0"
13
+ gem "jeweler", "~> 1.5.1"
14
+ gem "rcov", ">= 0"
15
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,24 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ bluecloth (2.0.9)
5
+ builder (3.0.0)
6
+ git (1.2.5)
7
+ jeweler (1.5.1)
8
+ bundler (~> 1.0.0)
9
+ git (>= 1.2.5)
10
+ rake
11
+ rake (0.8.7)
12
+ rcov (0.9.9)
13
+ yard (0.6.3)
14
+
15
+ PLATFORMS
16
+ ruby
17
+
18
+ DEPENDENCIES
19
+ bluecloth
20
+ builder
21
+ bundler (~> 1.0.0)
22
+ jeweler (~> 1.5.1)
23
+ rcov
24
+ yard (~> 0.6.0)
data/README.md ADDED
@@ -0,0 +1,8 @@
1
+ # rui
2
+
3
+ GUI abstraction library for ruby.
4
+
5
+ ## Supported backends
6
+
7
+ * Qt
8
+ * KDE
data/Rakefile ADDED
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "rui"
16
+ gem.homepage = "http://github.com/pcapriotti/rui"
17
+ gem.license = "LGPL"
18
+ gem.description = %q{GUI abstraction library supporting Qt and KDE backends}
19
+ gem.summary = %q{GUI abstraction library}
20
+ gem.email = "p.capriotti@gmail.com"
21
+ gem.authors = ["Paolo Capriotti"]
22
+ gem.rubyforge_project = "nowarning"
23
+ end
24
+ Jeweler::RubygemsDotOrgTasks.new
25
+
26
+ require 'rake/testtask'
27
+ Rake::TestTask.new(:test) do |test|
28
+ test.libs << 'lib' << 'test'
29
+ test.pattern = 'test/**/test_*.rb'
30
+ test.verbose = true
31
+ end
32
+
33
+ require 'rcov/rcovtask'
34
+ Rcov::RcovTask.new do |test|
35
+ test.libs << 'test'
36
+ test.pattern = 'test/**/test_*.rb'
37
+ test.verbose = true
38
+ end
39
+
40
+ task :default => :test
41
+
42
+ require 'yard'
43
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,12 @@
1
+ require 'rui'
2
+
3
+ RUI::Application.init('autogui') do |app|
4
+ widget = Qt::Widget.new
5
+ widget.gui = RUI::autogui do
6
+ layout(:type => :vertical) do
7
+ button(:name => :quit, :text => "Quit")
8
+ end
9
+ end
10
+ widget.quit.on(:clicked) { app.exit }
11
+ widget.show
12
+ end
@@ -0,0 +1,13 @@
1
+ # Copyright (c) 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'
9
+
10
+ RUI::Application.init('hello') do
11
+ RUI::PushButton.new("Hello").show
12
+ end
13
+
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/ruby
2
+ $:.unshift('lib')
3
+ $toolkit = :kde
4
+ load "examples/#{ARGV.shift}/main.rb"
data/examples/qtrun.rb ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/ruby
2
+ $:.unshift('lib')
3
+ $toolkit = :qt
4
+ load "examples/#{ARGV[0]}/main.rb"
@@ -0,0 +1,15 @@
1
+ # Copyright (c) 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'
9
+
10
+ RUI::Application.init('signals') do |app|
11
+ button = RUI::PushButton.new("Quit")
12
+ button.on(:clicked) { app.exit }
13
+ button.show
14
+ end
15
+
@@ -0,0 +1,241 @@
1
+ # Copyright (c) 2009 Paolo Capriotti <p.capriotti@gmail.com>
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation; either version 2 of the License, or
6
+ # (at your option) any later version.
7
+
8
+ #
9
+ # A <b>descriptor</b> is a rose tree with arbitrary properties at each node, used to
10
+ # define GUIs declaratively.
11
+ #
12
+ # Descriptors can be created using a DSL. For example:
13
+ #
14
+ # ex1 = Descriptor.build(:root, :name => 'parent') do
15
+ # child :name => 'foo'
16
+ # child :name => 'bar'
17
+ # merge_point
18
+ # child :name => 'hello' do
19
+ # grandchild :name => 'world'
20
+ # end
21
+ # end
22
+ #
23
+ # creates a tree which has a node with no name and three children with names
24
+ # 'foo', 'bar', and 'hello', and hello having a child of its own, called
25
+ # 'world'. Note that <b>descriptor tags</b> (<tt>:root</tt>, <tt>:child</tt> and
26
+ # <tt>:grandchild</tt> in the example) are completely arbitrary, but they play
27
+ # a special role when merging, together with the <tt>:name</tt> property.
28
+ #
29
+ # <b>Merging</b> consists of taking two descriptor trees, and matching their roots by
30
+ # tag and name. If they match, their children are recursively matched and
31
+ # merged, or simply concatenated when no match is found.
32
+ #
33
+ # For example, if <tt>ex1</tt> above is merged with the following descriptor:
34
+ #
35
+ # ex2 = Descriptor.build(:root, :name => 'parent') do
36
+ # child :name => 'foo2'
37
+ # child :name => 'hello' do
38
+ # grandchild :name => 'world2'
39
+ # end
40
+ # end
41
+ #
42
+ # the resulting descriptor would be equivalent to the one created by:
43
+ #
44
+ # ex1_merged_with_ex2 = Descriptor.build(:root, :name => 'parent') do
45
+ # child :name => 'foo'
46
+ # child :name => 'bar'
47
+ # child :name => 'foo2'
48
+ # child :name => 'hello' do
49
+ # grandchild :name => 'world'
50
+ # grandchild :name => 'world2'
51
+ # end
52
+ # end
53
+ #
54
+ # As can be seen in the example, <b>merge points</b> can be used to specify exactly
55
+ # where children of merged descriptors should be inserted.
56
+ #
57
+ # Merge points can optionally have a <tt>count</tt>, which specifies the number
58
+ # of children to be inserted on that particular point. When the count is
59
+ # satisfied, additional children are added at the following merge point, or, if
60
+ # no more merge points exist, at the bottom.
61
+ #
62
+ class Descriptor
63
+ attr_reader :tag # @return [Symbol] the descriptor tag
64
+ attr_reader :opts # @return [Hash] properties for this descriptor
65
+ attr_reader :children # @return [Array] children of this descriptor
66
+
67
+ #
68
+ # Create a descriptor using the DSL.
69
+ # @param tag [Symbol] descriptor tag
70
+ # @param opts [Hash] arbitrary hash of properties
71
+ # @return [Descriptor]
72
+ #
73
+ def self.build(tag, opts = { }, &blk)
74
+ root = new(tag, opts)
75
+ builder = Builder.new(root)
76
+ builder.instance_eval(&blk) if block_given?
77
+ root
78
+ end
79
+
80
+ #
81
+ # Create a descriptor with no children.
82
+ # @param tag [Symbol] descriptor tag
83
+ # @param opts [Hash] arbitrary hash of properties
84
+ #
85
+ def initialize(tag, opts = { })
86
+ @tag = tag
87
+ @opts = opts
88
+ @children = []
89
+ end
90
+
91
+ #
92
+ # Add a child to this descriptor.
93
+ #
94
+ def add_child(desc)
95
+ @children << desc
96
+ end
97
+
98
+ #
99
+ # Add a child to this descriptor, taking merge points into account.
100
+ #
101
+ def merge_child(desc)
102
+ mp = @opts[:merge_points].first if @opts[:merge_points]
103
+ if mp
104
+ @children.insert(mp.position, desc)
105
+ @opts[:merge_points].step!
106
+ else
107
+ add_child(desc)
108
+ end
109
+ end
110
+
111
+ #
112
+ # Add a merge point to this descriptor. Newly added merge points will not
113
+ # affect existing children, even if they were added with <tt>merge_child</tt>
114
+ # @param position merge point position
115
+ # @param count maximum number of children that can be merged at this point.
116
+ # If negative, no limit on the number of mergeable children is set.
117
+ #
118
+ def add_merge_point(position, count = -1)
119
+ mp = MergePoint.new(position, count)
120
+ @opts[:merge_points] ||= MergePoint::List.new
121
+ @opts[:merge_points].add(mp)
122
+ mp
123
+ end
124
+
125
+ #
126
+ # Convert this descriptor to a human readable sexp representation. Descriptor
127
+ # properties are printed as ruby hashes.
128
+ #
129
+ def to_sexp
130
+ "(#{@tag} #{@opts.inspect}#{@children.map{|c| ' ' + c.to_sexp}.join})"
131
+ end
132
+
133
+ #
134
+ # Destructively merge this descriptor with another.
135
+ #
136
+ # Descriptors are merged if they match by tag and name, or if this descriptor
137
+ # has tag <tt>:group</tt> and the other one has a property <tt>:group</tt>
138
+ # set to the name of this descriptor.
139
+ #
140
+ # @param other the descriptor to be merged
141
+ # @return [Boolean] whether the merge was successful
142
+ #
143
+ def merge!(other)
144
+ if tag == other.tag and
145
+ opts[:name] == other.opts[:name]
146
+ # if roots match
147
+ other.children.each do |child2|
148
+ # merge each of the children of the second descriptor
149
+ merged = false
150
+ children.each do |child|
151
+ # try to match with any of the children of the first descriptor
152
+ if child.merge!(child2)
153
+ merged = true
154
+ break
155
+ end
156
+ end
157
+ # if no match is found, just add it as a child of the root
158
+ merge_child(child2.dup) unless merged
159
+ end
160
+ true
161
+ elsif tag == :group and other.opts[:group] == opts[:name]
162
+ # if the root is the group of the second descriptor, add it as a child
163
+ merge_child(other)
164
+ else
165
+ false
166
+ end
167
+ end
168
+
169
+ class MergePoint
170
+ attr_accessor :position, :count
171
+
172
+ class List
173
+ def initialize
174
+ @mps = []
175
+ end
176
+
177
+ def first
178
+ @mps.first
179
+ end
180
+
181
+ def add(mp)
182
+ @mps << mp
183
+ end
184
+
185
+ def step!
186
+ raise "Stepping invalid merge point list" if @mps.empty?
187
+ @mps.each do |mp|
188
+ mp.position += 1
189
+ end
190
+ @mps.first.count -= 1
191
+ clean!
192
+ end
193
+
194
+ private
195
+
196
+ def clean!
197
+ @mps.delete_if {|mp| not mp.valid? }
198
+ end
199
+ end
200
+
201
+ def initialize(position, count = -1)
202
+ @position = position
203
+ @count = count
204
+ raise "Creating invalid merge point" if @count == 0
205
+ end
206
+
207
+ def valid?
208
+ @count != 0
209
+ end
210
+ end
211
+
212
+ class Builder
213
+ attr_reader :__desc__
214
+ private :__desc__
215
+
216
+ def initialize(desc)
217
+ @__desc__ = desc
218
+ end
219
+
220
+ def method_missing(name, *args, &blk)
221
+ opts = if args.empty?
222
+ { }
223
+ elsif args.size == 1
224
+ if args.first.is_a? Hash
225
+ args.first
226
+ else
227
+ { :name => args.first }
228
+ end
229
+ else
230
+ args[-1].merge(:name => args.first)
231
+ end
232
+ child = Descriptor.new(name, opts)
233
+ self.class.new(child).instance_eval(&blk) if block_given?
234
+ __desc__.add_child(child)
235
+ end
236
+
237
+ def merge_point(count = -1)
238
+ @__desc__.add_merge_point(@__desc__.children.size, count)
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,84 @@
1
+ # Copyright (c) 2009 Paolo Capriotti <p.capriotti@gmail.com>
2
+ #
3
+ # This program is free software; you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation; either version 2 of the License, or
6
+ # (at your option) any later version.
7
+
8
+ class Proc
9
+ #
10
+ # Bind this Proc to an object.
11
+ #
12
+ def bind(object)
13
+ block, time = self, Time.now
14
+ (class << object; self end).class_eval do
15
+ method_name = "__bind_#{time.to_i}_#{time.usec}"
16
+ define_method(method_name, &block)
17
+ method = instance_method(method_name)
18
+ remove_method(method_name)
19
+ method
20
+ end.bind(object)
21
+ end
22
+ end
23
+
24
+ #
25
+ # A Factory is a wrapper around a Proc that exposes it through its {Factory#new
26
+ # new} method.
27
+ #
28
+ # Wrapping a Proc in a Factory is useful to have a uniform API across classes
29
+ # and custom object-creating lambdas. For instance, if a method create_object
30
+ # takes a class as argument, like:
31
+ #
32
+ # def create_object(klass)
33
+ # obj = klass.new('foo')
34
+ # # do something with obj
35
+ # obj
36
+ # end
37
+ #
38
+ # you can pass modified class constructors:
39
+ #
40
+ # create_object(Factory.new {|arg| Array.new(4) { arg } })
41
+ #
42
+ # and have the method behave as if the passed argument were a normal class.
43
+ #
44
+ class Factory
45
+ #
46
+ # A Factory can specify a <b>component</b>, which is the class used to
47
+ # instantiate the objects created by this Factory.
48
+ #
49
+ # When non-nil, it should satisfy <tt>component == new(*args).class</tt>.
50
+ #
51
+ # @return the component of this Factory
52
+ #
53
+ attr_reader :component
54
+
55
+ #
56
+ # Create a factory object.
57
+ #
58
+ # @param component[Class] the factory component
59
+ # @param &blk the wrapped Proc
60
+ #
61
+ def initialize(component = nil, &blk)
62
+ @blk = blk
63
+ @component = component
64
+ end
65
+
66
+ #
67
+ # Call the wrapped Proc
68
+ #
69
+ def new(*args)
70
+ @blk[*args]
71
+ end
72
+
73
+ #
74
+ # Rebind this Factory.
75
+ #
76
+ # Binding a Factory to an object causes the wrapped Proc to be executed in
77
+ # the given object's scope.
78
+ #
79
+ # @param object the object to bind this Factory to
80
+ #
81
+ def __bind__(object)
82
+ Factory.new(@component, &@blk.bind(object))
83
+ end
84
+ end